From 1d1a95656a185586d5aeba1787a102fffecbe6e3 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 31 Jul 2018 18:48:32 -0700 Subject: [PATCH 01/11] 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 cf63f1f4d224..22f592790928 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 000000000000..0a6b4dfb198b --- /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 000000000000..9ad36b8d286a --- /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 000000000000..059d0d1dbb3e --- /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) +} From 804baa70f442c5d23c70bf0bdb934a4fb1659790 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Fri, 3 Aug 2018 12:55:00 -0700 Subject: [PATCH 02/11] added querier to gov module --- baseapp/baseapp.go | 14 +++- baseapp/queryrouter.go | 10 +-- types/queryable.go | 5 +- x/gov/keeper.go | 60 ++++++++++++++ x/gov/queryable.go | 183 +++++++++++++++++++++++++++++++++-------- 5 files changed, 227 insertions(+), 45 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 22f592790928..8f08d2abfc63 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -393,10 +393,18 @@ func handleQueryP2P(app *BaseApp, path []string, req abci.RequestQuery) (res abc func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { // "/custom" prefix for keeper queries - queryable := app.queryrouter.Route(path[1]) + querier := app.queryrouter.Route(path[1]) ctx := app.checkState.ctx - res, err := queryable.Query(ctx, path[2:], req) - return + resBytes, err := querier(ctx, path[2:], req) + if err != nil { + return abci.ResponseQuery{ + Code: uint32(err.ABCICode()), + } + } + return abci.ResponseQuery{ + Code: uint32(sdk.ABCICodeOK), + Value: resBytes, + } } // BeginBlock implements the ABCI application interface. diff --git a/baseapp/queryrouter.go b/baseapp/queryrouter.go index 0a6b4dfb198b..ade071f1f715 100644 --- a/baseapp/queryrouter.go +++ b/baseapp/queryrouter.go @@ -6,14 +6,14 @@ import ( // QueryRouter provides queryables for each query path. type QueryRouter interface { - AddRoute(r string, h sdk.CustomQueryable) (rtr QueryRouter) - Route(path string) (h sdk.CustomQueryable) + AddRoute(r string, h sdk.Querier) (rtr QueryRouter) + Route(path string) (h sdk.Querier) } // map a transaction type to a handler and an initgenesis function type queryroute struct { r string - h sdk.CustomQueryable + h sdk.Querier } type queryrouter struct { @@ -30,7 +30,7 @@ func NewQueryRouter() *queryrouter { } // AddRoute - TODO add description -func (rtr *queryrouter) AddRoute(r string, h sdk.CustomQueryable) QueryRouter { +func (rtr *queryrouter) AddRoute(r string, h sdk.Querier) QueryRouter { if !isAlphaNumeric(r) { panic("route expressions can only contain alphanumeric characters") } @@ -41,7 +41,7 @@ func (rtr *queryrouter) AddRoute(r string, h sdk.CustomQueryable) QueryRouter { // Route - TODO add description // TODO handle expressive matches. -func (rtr *queryrouter) Route(path string) (h sdk.CustomQueryable) { +func (rtr *queryrouter) Route(path string) (h sdk.Querier) { for _, route := range rtr.routes { if route.r == path { return route.h diff --git a/types/queryable.go b/types/queryable.go index 9ad36b8d286a..9223332bc833 100644 --- a/types/queryable.go +++ b/types/queryable.go @@ -2,6 +2,5 @@ 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) -} +// Type for querier functions on keepers to implement to handle custom queries +type Querier = func(ctx Context, path []string, req abci.RequestQuery) (res []byte, err Error) diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 8a23ad24853c..45af4b471d9b 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -108,6 +108,52 @@ func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposal Proposal) { store.Delete(KeyProposal(proposal.GetProposalID())) } +// nolint: gocyclo +// Get Proposal from store by ProposalID +func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddress, depositerAddr sdk.AccAddress, status ProposalStatus, numLatest int64) []Proposal { + + maxProposalID, err := keeper.peekCurrentProposalID(ctx) + if err != nil { + return nil + } + + matchingProposals := []Proposal{} + + if numLatest <= 0 { + numLatest = maxProposalID + } + + for proposalID := maxProposalID - numLatest; proposalID < maxProposalID; proposalID++ { + if voterAddr != nil && len(voterAddr) != 0 { + _, found := keeper.GetVote(ctx, proposalID, voterAddr) + if !found { + continue + } + } + + if depositerAddr != nil && len(depositerAddr) != 0 { + _, found := keeper.GetDeposit(ctx, proposalID, depositerAddr) + if !found { + continue + } + } + + proposal := keeper.GetProposal(ctx, proposalID) + if proposal == nil { + continue + } + + if validProposalStatus(status) { + if proposal.GetStatus() != status { + continue + } + } + + matchingProposals = append(matchingProposals, proposal) + } + return matchingProposals +} + func (keeper Keeper) setInitialProposalID(ctx sdk.Context, proposalID int64) sdk.Error { store := ctx.KVStore(keeper.storeKey) bz := store.Get(KeyNextProposalID) @@ -131,6 +177,7 @@ func (keeper Keeper) GetLastProposalID(ctx sdk.Context) (proposalID int64) { return } +// Gets the next available ProposalID and increments it func (keeper Keeper) getNewProposalID(ctx sdk.Context) (proposalID int64, err sdk.Error) { store := ctx.KVStore(keeper.storeKey) bz := store.Get(KeyNextProposalID) @@ -143,6 +190,19 @@ func (keeper Keeper) getNewProposalID(ctx sdk.Context) (proposalID int64, err sd return proposalID, nil } +// Peeks the next available ProposalID without incrementing it +func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID int64, err sdk.Error) { + store := ctx.KVStore(keeper.storeKey) + bz := store.Get(KeyNextProposalID) + if bz == nil { + return -1, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set") + } + keeper.cdc.MustUnmarshalBinary(bz, &proposalID) + bz = keeper.cdc.MustMarshalBinary(proposalID + 1) + store.Set(KeyNextProposalID, bz) + return proposalID, nil +} + func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) { proposal.SetVotingStartBlock(ctx.BlockHeight()) proposal.SetStatus(StatusVotingPeriod) diff --git a/x/gov/queryable.go b/x/gov/queryable.go index 059d0d1dbb3e..c0e66d0bf7ba 100644 --- a/x/gov/queryable.go +++ b/x/gov/queryable.go @@ -5,52 +5,167 @@ import ( abci "github.com/tendermint/tendermint/abci/types" ) -type Querier struct { - keeper Keeper +func NewQuerier(keeper Keeper) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + switch path[0] { + case "proposal": + return queryProposal(ctx, path[1:], req, keeper) + case "deposit": + return queryDeposit(ctx, path[1:], req, keeper) + case "vote": + return queryVote(ctx, path[1:], req, keeper) + case "deposits": + return queryDeposits(ctx, path[1:], req, keeper) + case "votes": + return queryVotes(ctx, path[1:], req, keeper) + case "proposals": + return queryProposals(ctx, path[1:], req, keeper) + case "tally": + return queryTally(ctx, path[1:], req, keeper) + default: + return nil, sdk.ErrUnknownRequest("unknown gov query endpoint") + } + } +} + +// Params for query 'custom/gov/proposal' +type QueryProposalParams struct { + ProposalID int64 } -func NewQuerier(keeper Keeper) { - return Querier{ - keeper: keeper, +func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { + var params QueryProposalParams + err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + if err2 != nil { + return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") + } + + proposal := keeper.GetProposal(ctx, params.ProposalID) + if proposal == nil { + return []byte{}, ErrUnknownProposal(DefaultCodespace, params.ProposalID) } + return keeper.cdc.MustMarshalBinary(proposal), nil } -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() +// Params for query 'custom/gov/deposit' +type QueryDepositParams struct { + ProposalID int64 + Depositer sdk.AccAddress +} + +func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { + var params QueryDepositParams + err2 := keeper.cdc.UnmarshalBinary(req.Data, params) + if err2 != nil { + return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") } + + deposit, _ := keeper.GetDeposit(ctx, params.ProposalID, params.Depositer) + return keeper.cdc.MustMarshalBinary(deposit), nil } -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() +// Params for query 'custom/gov/vote' +type QueryVoteParams struct { + ProposalID int64 + Voter sdk.AccAddress +} + +func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { + var params QueryVoteParams + err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + if err2 != nil { + return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") } - proposal := keeper.GetProposal(ctx, proposalID) - if proposal == nil { - return []byte{}, ErrUnknownProposal(DefaultCodespace, proposalID) + + vote, _ := keeper.GetVote(ctx, params.ProposalID, params.Voter) + return keeper.cdc.MustMarshalBinary(vote), nil +} + +// Params for query 'custom/gov/deposits' +type QueryDepositsParams struct { + ProposalID int64 +} + +func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { + var params QueryDepositParams + err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + if err2 != nil { + return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") } - return keeper.cdc.MustMarshalBinary(proposal), nil + + var deposits []Deposit + depositsIterator := keeper.GetDeposits(ctx, params.ProposalID) + for ; depositsIterator.Valid(); depositsIterator.Next() { + deposit := Deposit{} + keeper.cdc.MustUnmarshalBinary(depositsIterator.Value(), &deposit) + deposits = append(deposits, deposit) + } + + return keeper.cdc.MustMarshalBinary(deposits), 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() +// Params for query 'custom/gov/votes' +type QueryVotesParams struct { + ProposalID int64 +} + +func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { + var params QueryVotesParams + err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + if err2 != nil { + return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") } - proposal := keeper.GetProposal(ctx, proposalID) - if proposal == nil { - return []byte{}, ErrUnknownProposal(DefaultCodespace, proposalID) + + var votes []Vote + votesIterator := keeper.GetVotes(ctx, params.ProposalID) + for ; votesIterator.Valid(); votesIterator.Next() { + vote := Vote{} + keeper.cdc.MustUnmarshalBinary(votesIterator.Value(), &vote) + votes = append(votes, vote) + } + + return keeper.cdc.MustMarshalBinary(votes), nil +} + +// Params for query 'custom/gov/proposals' +type QueryProposalsParams struct { + Voter sdk.AccAddress + Depositer sdk.AccAddress + ProposalStatus ProposalStatus + NumLatestProposals int64 +} + +func queryProposals(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { + var params QueryProposalsParams + err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + if err2 != nil { + return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") } - passes, _ := tally(ctx, keeper, proposal) + + proposals := keeper.GetProposalsFiltered(ctx, params.Voter, params.Depositer, params.ProposalStatus, params.NumLatestProposals) + + bz := keeper.cdc.MustMarshalBinary(proposals) + return bz, nil +} + +// Params for query 'custom/gov/tally' +type QueryTallyParams struct { + ProposalID int64 +} + +func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { + // TODO: Dependant on #1914 + + // var proposalID int64 + // err2 := keeper.cdc.UnmarshalBinary(req.Data, proposalID) + // if err2 != nil { + // return []byte{}, sdk.ErrUnknownRequest() + // } + + // proposal := keeper.GetProposal(ctx, proposalID) + // if proposal == nil { + // return []byte{}, ErrUnknownProposal(DefaultCodespace, proposalID) + // } + // _, tallyResult, _ := tally(ctx, keeper, proposal) + return nil, nil } From cc1d1fbcf71b73db123cac0b62ab4f63aee98f52 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Fri, 3 Aug 2018 14:43:13 -0700 Subject: [PATCH 03/11] moved queryrouter to behind baseapp seal --- baseapp/baseapp.go | 25 ------------------------- baseapp/setters.go | 6 ++++++ 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 8f08d2abfc63..6f143b15627d 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -137,31 +137,6 @@ 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() diff --git a/baseapp/setters.go b/baseapp/setters.go index 86a647d32c1a..ef88b7fe5608 100644 --- a/baseapp/setters.go +++ b/baseapp/setters.go @@ -74,6 +74,12 @@ func (app *BaseApp) Router() Router { } return app.router } +func (app *BaseApp) QueryRouter() QueryRouter { + if app.sealed { + panic("QueryRouter() on sealed BaseApp") + } + return app.queryrouter +} func (app *BaseApp) Seal() { app.sealed = true } func (app *BaseApp) IsSealed() bool { return app.sealed } func (app *BaseApp) enforceSeal() { From 13111176584b6a72bd00e4e5509b133387ed587f Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Sun, 5 Aug 2018 01:56:48 -0400 Subject: [PATCH 04/11] added to gov rest --- client/context/query.go | 5 ++ cmd/gaia/app/app.go | 3 + types/account.go | 23 ++++++ x/gov/client/rest/rest.go | 167 +++++++++++++++++--------------------- x/gov/depositsvotes.go | 32 ++++++++ x/gov/queryable.go | 2 +- 6 files changed, 139 insertions(+), 93 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 081f723b5c9c..68676f7415dc 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -31,6 +31,11 @@ func (ctx CLIContext) Query(path string) (res []byte, err error) { return ctx.query(path, nil) } +// Query information about the connected node with a data payload +func (ctx CLIContext) QueryWithData(path string, data []byte) (res []byte, err error) { + return ctx.query(path, data) +} + // QueryStore performs a query from a Tendermint node with the provided key and // store name. func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (res []byte, err error) { diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index a96efa6b174f..f79ffb3065ff 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -105,6 +105,9 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio AddRoute("slashing", slashing.NewHandler(app.slashingKeeper)). AddRoute("gov", gov.NewHandler(app.govKeeper)) + app.QueryRouter(). + AddRoute("gov", gov.NewQuerier(app.govKeeper)) + // initialize BaseApp app.SetInitChainer(app.initChainer) app.SetBeginBlocker(app.BeginBlocker) diff --git a/types/account.go b/types/account.go index 92e2988f2470..258a095e8b78 100644 --- a/types/account.go +++ b/types/account.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "encoding/hex" "encoding/json" "errors" @@ -108,6 +109,17 @@ func (bz AccAddress) Format(s fmt.State, verb rune) { } } +// Returns boolean for whether two AccAddresses are Equal +func (bz AccAddress) Equals(bz2 AccAddress) bool { + return (bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0) +} + +// Returns boolean for whether an AccAddress is empty +func (bz AccAddress) Empty() bool { + bz2 := AccAddress{} + return bz.Equals(bz2) +} + //__________________________________________________________ // AccAddress a wrapper around bytes meant to represent a validator address @@ -192,6 +204,17 @@ func (bz ValAddress) Format(s fmt.State, verb rune) { } } +// Returns boolean for whether two ValAddresses are Equal +func (bz ValAddress) Equals(bz2 ValAddress) bool { + return (bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0) +} + +// Returns boolean for whether an AccAddress is empty +func (bz ValAddress) Empty() bool { + bz2 := ValAddress{} + return bz.Equals(bz2) +} + // Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string func Bech32ifyAccPub(pub crypto.PubKey) (string, error) { return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes()) diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 22283a652e19..cf5481da8c42 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -21,6 +21,7 @@ const ( RestDepositer = "depositer" RestVoter = "voter" RestProposalStatus = "status" + RestNumLatest = "latest" storeName = "gov" ) @@ -190,9 +191,13 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) - if err != nil || len(res) == 0 { - err := errors.Errorf("proposalID [%d] does not exist", proposalID) + params := gov.QueryProposalParams{ + ProposalID: proposalID, + } + + res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinary(params)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return @@ -255,19 +260,14 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := cliCtx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName) - if err != nil || len(res) == 0 { - res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) - if err != nil || len(res) == 0 { - w.WriteHeader(http.StatusNotFound) - err := errors.Errorf("proposalID [%d] does not exist", proposalID) - w.Write([]byte(err.Error())) - - return - } + params := gov.QueryDepositParams{ + ProposalID: proposalID, + Depositer: depositerAddr, + } - w.WriteHeader(http.StatusNotFound) - err = errors.Errorf("depositer [%s] did not deposit on proposalID [%d]", bechDepositerAddr, proposalID) + res, err := cliCtx.QueryWithData("custom/gov/deposit", cdc.MustMarshalBinary(params)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return @@ -283,7 +283,19 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { return } - + if deposit.Empty() { + res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinary(gov.QueryProposalParams{params.ProposalID})) + if err != nil || len(res) == 0 { + w.WriteHeader(http.StatusNotFound) + err := errors.Errorf("proposalID [%d] does not exist", proposalID) + w.Write([]byte(err.Error())) + return + } + w.WriteHeader(http.StatusNotFound) + err = errors.Errorf("depositer [%s] did not deposit on proposalID [%d]", bechDepositerAddr, proposalID) + w.Write([]byte(err.Error())) + return + } w.Write(output) } } @@ -328,19 +340,14 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) - if err != nil || len(res) == 0 { - res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) - if err != nil || len(res) == 0 { - w.WriteHeader(http.StatusNotFound) - err := errors.Errorf("proposalID [%d] does not exist", proposalID) - w.Write([]byte(err.Error())) - - return - } + params := gov.QueryVoteParams{ + Voter: voterAddr, + ProposalID: proposalID, + } - w.WriteHeader(http.StatusNotFound) - err = errors.Errorf("voter [%s] did not vote on proposalID [%d]", bechVoterAddr, proposalID) + res, err := cliCtx.QueryWithData("custom/gov/vote", cdc.MustMarshalBinary(params)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return @@ -356,7 +363,19 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { return } - + if vote.Empty() { + res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinary(gov.QueryProposalParams{params.ProposalID})) + if err != nil || len(res) == 0 { + w.WriteHeader(http.StatusNotFound) + err := errors.Errorf("proposalID [%d] does not exist", proposalID) + w.Write([]byte(err.Error())) + return + } + w.WriteHeader(http.StatusNotFound) + err = errors.Errorf("voter [%s] did not deposit on proposalID [%d]", bechVoterAddr, proposalID) + w.Write([]byte(err.Error())) + return + } w.Write(output) } } @@ -387,38 +406,19 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) - if err != nil || len(res) == 0 { - err := errors.Errorf("proposalID [%d] does not exist", proposalID) - w.Write([]byte(err.Error())) - - return + params := gov.QueryVotesParams{ + ProposalID: proposalID, } - var proposal gov.Proposal - cdc.MustUnmarshalBinary(res, &proposal) - - if proposal.GetStatus() != gov.StatusVotingPeriod { - err := errors.Errorf("proposal is not in Voting Period", proposalID) - w.Write([]byte(err.Error())) - - return - } - - res2, err := cliCtx.QuerySubspace(gov.KeyVotesSubspace(proposalID), storeName) + res, err := cliCtx.QueryWithData("custom/gov/votes", cdc.MustMarshalBinary(params)) if err != nil { - err = errors.New("ProposalID doesn't exist") + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } var votes []gov.Vote - - for i := 0; i < len(res2); i++ { - var vote gov.Vote - cdc.MustUnmarshalBinary(res2[i].Value, &vote) - votes = append(votes, vote) - } + cdc.MustUnmarshalBinary(res, &votes) output, err := wire.MarshalJSONIndent(cdc, votes) if err != nil { @@ -439,11 +439,13 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { bechVoterAddr := r.URL.Query().Get(RestVoter) bechDepositerAddr := r.URL.Query().Get(RestDepositer) strProposalStatus := r.URL.Query().Get(RestProposalStatus) + strNumLatest := r.URL.Query().Get(RestNumLatest) var err error var voterAddr sdk.AccAddress var depositerAddr sdk.AccAddress var proposalStatus gov.ProposalStatus + var numLatest int64 if len(bechVoterAddr) != 0 { voterAddr, err = sdk.AccAddressFromBech32(bechVoterAddr) @@ -476,54 +478,35 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { return } } + if len(strNumLatest) != 0 { + numLatest, err = strconv.ParseInt(strNumLatest, 10, 64) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + err := errors.Errorf("'%s' is not a valid int64", strNumLatest) + w.Write([]byte(err.Error())) + return + } + } cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := cliCtx.QueryStore(gov.KeyNextProposalID, storeName) + params := gov.QueryProposalsParams{ + Depositer: depositerAddr, + Voter: voterAddr, + ProposalStatus: proposalStatus, + NumLatestProposals: numLatest, + } + + res, err := cliCtx.QueryWithData("custom/gov/proposals", cdc.MustMarshalBinary(params)) if err != nil { - err = errors.New("no proposals exist yet and proposalID has not been set") + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } - var maxProposalID int64 - cdc.MustUnmarshalBinary(res, &maxProposalID) - - matchingProposals := []gov.Proposal{} - - for proposalID := int64(0); proposalID < maxProposalID; proposalID++ { - if voterAddr != nil { - res, err = cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName) - if err != nil || len(res) == 0 { - continue - } - } - - if depositerAddr != nil { - res, err = cliCtx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName) - if err != nil || len(res) == 0 { - continue - } - } - - res, err = cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName) - if err != nil || len(res) == 0 { - continue - } - - var proposal gov.Proposal - cdc.MustUnmarshalBinary(res, &proposal) - - if len(strProposalStatus) != 0 { - if proposal.GetStatus() != proposalStatus { - continue - } - } - - matchingProposals = append(matchingProposals, proposal) - } - + var matchingProposals []gov.Proposal + cdc.MustUnmarshalBinary(res, &matchingProposals) output, err := wire.MarshalJSONIndent(cdc, matchingProposals) if err != nil { w.WriteHeader(http.StatusBadRequest) diff --git a/x/gov/depositsvotes.go b/x/gov/depositsvotes.go index 19ed97f69d28..5a8b6bf24997 100644 --- a/x/gov/depositsvotes.go +++ b/x/gov/depositsvotes.go @@ -15,6 +15,22 @@ type Vote struct { Option VoteOption `json:"option"` // option from OptionSet chosen by the voter } +// Returns whether 2 votes are equal +func (voteA Vote) Equals(voteB Vote) bool { + if voteA.Voter.Equals(voteB.Voter) && + voteA.ProposalID == voteB.ProposalID && + voteA.Option == voteB.Option { + return true + } + return false +} + +// Returns whether a vote is empty +func (voteA Vote) Empty() bool { + voteB := Vote{} + return voteA.Equals(voteB) +} + // Deposit type Deposit struct { Depositer sdk.AccAddress `json:"depositer"` // Address of the depositer @@ -22,6 +38,22 @@ type Deposit struct { Amount sdk.Coins `json:"amount"` // Deposit amount } +// Returns whether 2 deposits are equal +func (depositA Deposit) Equals(depositB Deposit) bool { + if depositA.Depositer.Equals(depositB.Depositer) && + depositA.ProposalID == depositB.ProposalID && + depositA.Amount.IsEqual(depositB.Amount) { + return true + } + return false +} + +// Returns whether a deposit is empty +func (depositA Deposit) Empty() bool { + depositB := Deposit{} + return depositA.Equals(depositB) +} + // Type that represents VoteOption as a byte type VoteOption byte diff --git a/x/gov/queryable.go b/x/gov/queryable.go index c0e66d0bf7ba..13bdfd08dc03 100644 --- a/x/gov/queryable.go +++ b/x/gov/queryable.go @@ -55,7 +55,7 @@ type QueryDepositParams struct { func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { var params QueryDepositParams - err2 := keeper.cdc.UnmarshalBinary(req.Data, params) + err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) if err2 != nil { return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") } From 0eed9d1b60375dae6ff0d0d7104a5cb727988cac Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Mon, 6 Aug 2018 05:09:16 -0400 Subject: [PATCH 05/11] PENDING --- PENDING.md | 1 + docs/sdk/modules.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/PENDING.md b/PENDING.md index c4b04238cd25..53bdb91cac13 100644 --- a/PENDING.md +++ b/PENDING.md @@ -33,6 +33,7 @@ FEATURES * Gaia * SDK + * [querier] added custom querier functionality, so ABCI query requests can be handled by keepers * Tendermint diff --git a/docs/sdk/modules.md b/docs/sdk/modules.md index b9249cf3e993..7df8fb2bb0bb 100644 --- a/docs/sdk/modules.md +++ b/docs/sdk/modules.md @@ -6,7 +6,7 @@ The Cosmos SDK has all the necessary pre-built modules to add functionality on top of a `BaseApp`, which is the template to build a blockchain dApp in Cosmos. In this context, a `module` is a fundamental unit in the Cosmos SDK. -Each module is an extension of the `BaseApp`'s functionalities that defines transactions, handles application state and manages the state transition logic. Each module also contains handlers for messages and transactions, as well as REST and CLI for secure user interactions. +Each module is an extension of the `BaseApp`'s functionalities that defines transactions, handles application state and manages the state transition logic. Each module also contains handlers for messages and transactions, queriers for handling query requests, as well as REST and CLI for secure user interactions. Some of the most important modules in the SDK are: From 0134c3b7f1d96278308e229ace4a956101a351b8 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Wed, 15 Aug 2018 17:59:15 -0700 Subject: [PATCH 06/11] Address Anton's comments --- baseapp/baseapp.go | 12 ++++++--- baseapp/setters.go | 2 +- x/gov/client/rest/rest.go | 57 ++++++++++++--------------------------- x/gov/client/rest/util.go | 14 ++++++++++ x/gov/depositsvotes.go | 14 ++-------- x/gov/keeper.go | 2 -- 6 files changed, 42 insertions(+), 59 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 6f143b15627d..aadea1561a4e 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -46,7 +46,7 @@ type BaseApp struct { 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 + queryRouter QueryRouter // router for redirecting query calls codespacer *sdk.Codespacer // handle module codespacing txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx @@ -90,7 +90,7 @@ func NewBaseApp(name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecod db: db, cms: store.NewCommitMultiStore(db), router: NewRouter(), - queryrouter: NewQueryRouter(), + queryRouter: NewQueryRouter(), codespacer: sdk.NewCodespacer(), txDecoder: txDecoder, } @@ -268,6 +268,7 @@ func (app *BaseApp) FilterPeerByPubKey(info string) abci.ResponseQuery { return abci.ResponseQuery{} } +// Splits a string path using the delimter '/'. i.e. "this/is/funny" becomes []string{"this", "is", "funny"} func splitPath(requestPath string) (path []string) { path = strings.Split(requestPath, "/") // first element is empty string @@ -367,9 +368,12 @@ func handleQueryP2P(app *BaseApp, path []string, req abci.RequestQuery) (res abc } func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { - // "/custom" prefix for keeper queries - querier := app.queryrouter.Route(path[1]) + // path[0] should be "custom" because "/custom" prefix is required for keeper queries. + // the queryRouter routes using path[1]. For example, in the path "custom/gov/proposal", queryRouter routes using "gov" + querier := app.queryRouter.Route(path[1]) ctx := app.checkState.ctx + // Passes the rest of the path as an argument to the querier. + // For example, in the path "custom/gov/proposal/test", the gov querier gets []string{"proposal", "test"} as the path resBytes, err := querier(ctx, path[2:], req) if err != nil { return abci.ResponseQuery{ diff --git a/baseapp/setters.go b/baseapp/setters.go index ef88b7fe5608..4bcae0ed7ca7 100644 --- a/baseapp/setters.go +++ b/baseapp/setters.go @@ -78,7 +78,7 @@ func (app *BaseApp) QueryRouter() QueryRouter { if app.sealed { panic("QueryRouter() on sealed BaseApp") } - return app.queryrouter + return app.queryRouter } func (app *BaseApp) Seal() { app.sealed = true } func (app *BaseApp) IsSealed() bool { return app.sealed } diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index cf5481da8c42..7e5843b3ded1 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -3,7 +3,6 @@ package rest import ( "fmt" "net/http" - "strconv" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" @@ -98,16 +97,13 @@ func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFu return } - proposalID, err := strconv.ParseInt(strProposalID, 10, 64) - if err != nil { - err := errors.Errorf("proposalID [%d] is not positive", proposalID) - w.Write([]byte(err.Error())) - + proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w) + if !ok { return } var req depositReq - err = buildReq(w, r, cdc, &req) + err := buildReq(w, r, cdc, &req) if err != nil { return } @@ -140,15 +136,13 @@ func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc return } - proposalID, err := strconv.ParseInt(strProposalID, 10, 64) - if err != nil { - err := errors.Errorf("proposalID [%d] is not positive", proposalID) - w.Write([]byte(err.Error())) + proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w) + if !ok { return } var req voteReq - err = buildReq(w, r, cdc, &req) + err := buildReq(w, r, cdc, &req) if err != nil { return } @@ -181,11 +175,8 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { return } - proposalID, err := strconv.ParseInt(strProposalID, 10, 64) - if err != nil { - err := errors.Errorf("proposalID [%d] is not positive", proposalID) - w.Write([]byte(err.Error())) - + proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w) + if !ok { return } @@ -232,12 +223,8 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { return } - proposalID, err := strconv.ParseInt(strProposalID, 10, 64) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - err := errors.Errorf("proposalID [%d] is not positive", proposalID) - w.Write([]byte(err.Error())) - + proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w) + if !ok { return } @@ -313,12 +300,8 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { return } - proposalID, err := strconv.ParseInt(strProposalID, 10, 64) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - err := errors.Errorf("proposalID [%s] is not positive", proposalID) - w.Write([]byte(err.Error())) - + proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w) + if !ok { return } @@ -395,12 +378,8 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { return } - proposalID, err := strconv.ParseInt(strProposalID, 10, 64) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - err := errors.Errorf("proposalID [%s] is not positive", proposalID) - w.Write([]byte(err.Error())) - + proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w) + if !ok { return } @@ -442,6 +421,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { strNumLatest := r.URL.Query().Get(RestNumLatest) var err error + var ok bool var voterAddr sdk.AccAddress var depositerAddr sdk.AccAddress var proposalStatus gov.ProposalStatus @@ -479,11 +459,8 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { } } if len(strNumLatest) != 0 { - numLatest, err = strconv.ParseInt(strNumLatest, 10, 64) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - err := errors.Errorf("'%s' is not a valid int64", strNumLatest) - w.Write([]byte(err.Error())) + numLatest, ok = parseInt64OrReturnBadRequest(strNumLatest, w) + if !ok { return } } diff --git a/x/gov/client/rest/util.go b/x/gov/client/rest/util.go index 58d96b591faa..de94a8324c84 100644 --- a/x/gov/client/rest/util.go +++ b/x/gov/client/rest/util.go @@ -1,8 +1,10 @@ package rest import ( + "fmt" "io/ioutil" "net/http" + "strconv" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" @@ -100,3 +102,15 @@ func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq base w.Write(output) } + +func parseInt64OrReturnBadRequest(s string, w http.ResponseWriter) (n int64, ok bool) { + var err error + n, err = strconv.ParseInt(s, 10, 64) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + err := fmt.Errorf("'%s' is not a valid int64", s) + w.Write([]byte(err.Error())) + return 0, false + } + return n, true + } \ No newline at end of file diff --git a/x/gov/depositsvotes.go b/x/gov/depositsvotes.go index 5a8b6bf24997..b5c65931fc7e 100644 --- a/x/gov/depositsvotes.go +++ b/x/gov/depositsvotes.go @@ -17,12 +17,7 @@ type Vote struct { // Returns whether 2 votes are equal func (voteA Vote) Equals(voteB Vote) bool { - if voteA.Voter.Equals(voteB.Voter) && - voteA.ProposalID == voteB.ProposalID && - voteA.Option == voteB.Option { - return true - } - return false + return voteA.Voter.Equals(voteB.Voter) && voteA.ProposalID == voteB.ProposalID && voteA.Option == voteB.Option } // Returns whether a vote is empty @@ -40,12 +35,7 @@ type Deposit struct { // Returns whether 2 deposits are equal func (depositA Deposit) Equals(depositB Deposit) bool { - if depositA.Depositer.Equals(depositB.Depositer) && - depositA.ProposalID == depositB.ProposalID && - depositA.Amount.IsEqual(depositB.Amount) { - return true - } - return false + return depositA.Depositer.Equals(depositB.Depositer) && depositA.ProposalID == depositB.ProposalID && depositA.Amount.IsEqual(depositB.Amount) } // Returns whether a deposit is empty diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 45af4b471d9b..19d842f1f368 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -198,8 +198,6 @@ func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID int64, e return -1, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set") } keeper.cdc.MustUnmarshalBinary(bz, &proposalID) - bz = keeper.cdc.MustMarshalBinary(proposalID + 1) - store.Set(KeyNextProposalID, bz) return proposalID, nil } From 97f7b88a9fd9f4cd72e2d2c7db5593cdf0c5fde8 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Thu, 16 Aug 2018 18:35:17 -0700 Subject: [PATCH 07/11] addressed Jae's comments --- baseapp/baseapp.go | 4 ++++ baseapp/queryrouter.go | 30 ++++++++++-------------------- types/account.go | 16 ++++++++++++++-- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index aadea1561a4e..828414f1e228 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -370,6 +370,9 @@ func handleQueryP2P(app *BaseApp, path []string, req abci.RequestQuery) (res abc func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { // path[0] should be "custom" because "/custom" prefix is required for keeper queries. // the queryRouter routes using path[1]. For example, in the path "custom/gov/proposal", queryRouter routes using "gov" + if path[1] == "" { + sdk.ErrUnknownRequest("No route for custom query specified").QueryResult() + } querier := app.queryRouter.Route(path[1]) ctx := app.checkState.ctx // Passes the rest of the path as an argument to the querier. @@ -378,6 +381,7 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res if err != nil { return abci.ResponseQuery{ Code: uint32(err.ABCICode()), + Log: err.ABCILog(), } } return abci.ResponseQuery{ diff --git a/baseapp/queryrouter.go b/baseapp/queryrouter.go index ade071f1f715..23cfad07218c 100644 --- a/baseapp/queryrouter.go +++ b/baseapp/queryrouter.go @@ -10,14 +10,8 @@ type QueryRouter interface { Route(path string) (h sdk.Querier) } -// map a transaction type to a handler and an initgenesis function -type queryroute struct { - r string - h sdk.Querier -} - type queryrouter struct { - routes []queryroute + routes map[string]sdk.Querier } // nolint @@ -25,27 +19,23 @@ type queryrouter struct { // TODO either make Function unexported or make return type (router) Exported func NewQueryRouter() *queryrouter { return &queryrouter{ - routes: make([]queryroute, 0), + routes: map[string]sdk.Querier{}, } } -// AddRoute - TODO add description -func (rtr *queryrouter) AddRoute(r string, h sdk.Querier) QueryRouter { +// AddRoute - Adds an sdk.Querier to the route provided. Panics on duplicate +func (rtr *queryrouter) AddRoute(r string, q sdk.Querier) QueryRouter { if !isAlphaNumeric(r) { panic("route expressions can only contain alphanumeric characters") } - rtr.routes = append(rtr.routes, queryroute{r, h}) - + if rtr.routes[r] != nil { + panic("route has already been initialized") + } + rtr.routes[r] = q return rtr } -// Route - TODO add description -// TODO handle expressive matches. +// Returns the sdk.Querier for a certain route path func (rtr *queryrouter) Route(path string) (h sdk.Querier) { - for _, route := range rtr.routes { - if route.r == path { - return route.h - } - } - return nil + return rtr.routes[path] } diff --git a/types/account.go b/types/account.go index 258a095e8b78..9f19c26287a4 100644 --- a/types/account.go +++ b/types/account.go @@ -111,13 +111,19 @@ func (bz AccAddress) Format(s fmt.State, verb rune) { // Returns boolean for whether two AccAddresses are Equal func (bz AccAddress) Equals(bz2 AccAddress) bool { + if bz.Empty() && bz2.Empty() { + return true + } return (bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0) } // Returns boolean for whether an AccAddress is empty func (bz AccAddress) Empty() bool { + if bz == nil { + return true + } bz2 := AccAddress{} - return bz.Equals(bz2) + return (bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0) } //__________________________________________________________ @@ -206,13 +212,19 @@ func (bz ValAddress) Format(s fmt.State, verb rune) { // Returns boolean for whether two ValAddresses are Equal func (bz ValAddress) Equals(bz2 ValAddress) bool { + if bz.Empty() && bz2.Empty() { + return true + } return (bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0) } // Returns boolean for whether an AccAddress is empty func (bz ValAddress) Empty() bool { + if bz == nil { + return true + } bz2 := ValAddress{} - return bz.Equals(bz2) + return (bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0) } // Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string From 44bf69e5647890f264b49c1620635f831bd32bb3 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Fri, 17 Aug 2018 00:16:17 -0700 Subject: [PATCH 08/11] run queries against cachewrapped commit state, not checkstate --- baseapp/baseapp.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 828414f1e228..365d7b31f249 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -374,7 +374,11 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res sdk.ErrUnknownRequest("No route for custom query specified").QueryResult() } querier := app.queryRouter.Route(path[1]) - ctx := app.checkState.ctx + if querier == nil { + sdk.ErrUnknownRequest(fmt.Sprintf("no custom querier found for route %s", path[1])).QueryResult() + } + + ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger) // Passes the rest of the path as an argument to the querier. // For example, in the path "custom/gov/proposal/test", the gov querier gets []string{"proposal", "test"} as the path resBytes, err := querier(ctx, path[2:], req) From 50dd53fec3bbb7694b7addb2511f948cee90c411 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Fri, 17 Aug 2018 00:40:30 -0700 Subject: [PATCH 09/11] added tally query route to gov --- x/gov/queryable.go | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/x/gov/queryable.go b/x/gov/queryable.go index 13bdfd08dc03..28e32eb67548 100644 --- a/x/gov/queryable.go +++ b/x/gov/queryable.go @@ -156,16 +156,25 @@ type QueryTallyParams struct { func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { // TODO: Dependant on #1914 - // var proposalID int64 - // err2 := keeper.cdc.UnmarshalBinary(req.Data, proposalID) - // if err2 != nil { - // return []byte{}, sdk.ErrUnknownRequest() - // } - - // proposal := keeper.GetProposal(ctx, proposalID) - // if proposal == nil { - // return []byte{}, ErrUnknownProposal(DefaultCodespace, proposalID) - // } - // _, tallyResult, _ := tally(ctx, keeper, proposal) - return nil, nil + var proposalID int64 + err2 := keeper.cdc.UnmarshalBinary(req.Data, proposalID) + if err2 != nil { + return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") + } + + proposal := keeper.GetProposal(ctx, proposalID) + if proposal == nil { + return []byte{}, ErrUnknownProposal(DefaultCodespace, proposalID) + } + + if proposal.GetStatus() == StatusDepositPeriod { + return keeper.cdc.MustMarshalBinaryBare(EmptyTallyResult()), nil + } + + if proposal.GetStatus() == StatusPassed || proposal.GetStatus() == StatusRejected { + return keeper.cdc.MustMarshalBinaryBare(proposal.GetTallyResult()), nil + } + + _, tallyResult, _ := tally(ctx, keeper, proposal) + return keeper.cdc.MustMarshalBinaryBare(tallyResult), nil } From 5ae20d2d511aafd89008ea43433c5366d5f12e78 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Wed, 22 Aug 2018 00:10:11 -0700 Subject: [PATCH 10/11] address Chris's comments --- baseapp/setters.go | 3 - types/account.go | 8 +-- x/gov/client/rest/rest.go | 116 ++++++++++++++++---------------------- x/gov/proposals.go | 4 ++ x/gov/queryable.go | 85 +++++++++++++++++++--------- 5 files changed, 117 insertions(+), 99 deletions(-) diff --git a/baseapp/setters.go b/baseapp/setters.go index 4bcae0ed7ca7..a8b1591a738a 100644 --- a/baseapp/setters.go +++ b/baseapp/setters.go @@ -75,9 +75,6 @@ func (app *BaseApp) Router() Router { return app.router } func (app *BaseApp) QueryRouter() QueryRouter { - if app.sealed { - panic("QueryRouter() on sealed BaseApp") - } return app.queryRouter } func (app *BaseApp) Seal() { app.sealed = true } diff --git a/types/account.go b/types/account.go index 9f19c26287a4..00076b52997d 100644 --- a/types/account.go +++ b/types/account.go @@ -114,7 +114,7 @@ func (bz AccAddress) Equals(bz2 AccAddress) bool { if bz.Empty() && bz2.Empty() { return true } - return (bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0) + return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0 } // Returns boolean for whether an AccAddress is empty @@ -123,7 +123,7 @@ func (bz AccAddress) Empty() bool { return true } bz2 := AccAddress{} - return (bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0) + return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0 } //__________________________________________________________ @@ -215,7 +215,7 @@ func (bz ValAddress) Equals(bz2 ValAddress) bool { if bz.Empty() && bz2.Empty() { return true } - return (bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0) + return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0 } // Returns boolean for whether an AccAddress is empty @@ -224,7 +224,7 @@ func (bz ValAddress) Empty() bool { return true } bz2 := ValAddress{} - return (bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0) + return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0 } // Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 7e5843b3ded1..5cdc7bda2bfe 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -186,26 +186,22 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { ProposalID: proposalID, } - res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinary(params)) + bz, err := cdc.MarshalJSON(params) if err != nil { - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) - return } - var proposal gov.Proposal - cdc.MustUnmarshalBinary(res, &proposal) - - output, err := wire.MarshalJSONIndent(cdc, proposal) + res, err := cliCtx.QueryWithData("custom/gov/proposal", bz) if err != nil { - w.WriteHeader(http.StatusBadRequest) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } - w.Write(output) + w.Write(res) } } @@ -252,24 +248,23 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { Depositer: depositerAddr, } - res, err := cliCtx.QueryWithData("custom/gov/deposit", cdc.MustMarshalBinary(params)) + bz, err := cdc.MarshalJSON(params) if err != nil { - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) - return } - var deposit gov.Deposit - cdc.MustUnmarshalBinary(res, &deposit) - - output, err := wire.MarshalJSONIndent(cdc, deposit) + res, err := cliCtx.QueryWithData("custom/gov/deposit", bz) if err != nil { - w.WriteHeader(http.StatusBadRequest) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } + + var deposit gov.Deposit + cdc.UnmarshalJSON(res, &deposit) if deposit.Empty() { res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinary(gov.QueryProposalParams{params.ProposalID})) if err != nil || len(res) == 0 { @@ -283,7 +278,8 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.Write([]byte(err.Error())) return } - w.Write(output) + + w.Write(res) } } @@ -327,27 +323,31 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { Voter: voterAddr, ProposalID: proposalID, } - - res, err := cliCtx.QueryWithData("custom/gov/vote", cdc.MustMarshalBinary(params)) + bz, err := cdc.MarshalJSON(params) if err != nil { - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) - return } - var vote gov.Vote - cdc.MustUnmarshalBinary(res, &vote) - - output, err := wire.MarshalJSONIndent(cdc, vote) + res, err := cliCtx.QueryWithData("custom/gov/vote", bz) if err != nil { - w.WriteHeader(http.StatusBadRequest) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } + + var vote gov.Vote + cdc.UnmarshalJSON(res, &vote) if vote.Empty() { - res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinary(gov.QueryProposalParams{params.ProposalID})) + bz, err := cdc.MarshalJSON(gov.QueryProposalParams{params.ProposalID}) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + res, err := cliCtx.QueryWithData("custom/gov/proposal", bz) if err != nil || len(res) == 0 { w.WriteHeader(http.StatusNotFound) err := errors.Errorf("proposalID [%d] does not exist", proposalID) @@ -359,7 +359,7 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { w.Write([]byte(err.Error())) return } - w.Write(output) + w.Write(res) } } @@ -388,26 +388,21 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { params := gov.QueryVotesParams{ ProposalID: proposalID, } - - res, err := cliCtx.QueryWithData("custom/gov/votes", cdc.MustMarshalBinary(params)) + bz, err := cdc.MarshalJSON(params) if err != nil { - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - var votes []gov.Vote - cdc.MustUnmarshalBinary(res, &votes) - - output, err := wire.MarshalJSONIndent(cdc, votes) + res, err := cliCtx.QueryWithData("custom/gov/votes", bz) if err != nil { - w.WriteHeader(http.StatusBadRequest) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) - return } - w.Write(output) + w.Write(res) } } @@ -420,25 +415,21 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { strProposalStatus := r.URL.Query().Get(RestProposalStatus) strNumLatest := r.URL.Query().Get(RestNumLatest) - var err error - var ok bool - var voterAddr sdk.AccAddress - var depositerAddr sdk.AccAddress - var proposalStatus gov.ProposalStatus - var numLatest int64 + params := gov.QueryProposalsParams{} if len(bechVoterAddr) != 0 { - voterAddr, err = sdk.AccAddressFromBech32(bechVoterAddr) + voterAddr, err := sdk.AccAddressFromBech32(bechVoterAddr) if err != nil { w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter) w.Write([]byte(err.Error())) return } + params.Voter = voterAddr } if len(bechDepositerAddr) != 0 { - depositerAddr, err = sdk.AccAddressFromBech32(bechDepositerAddr) + depositerAddr, err := sdk.AccAddressFromBech32(bechDepositerAddr) if err != nil { w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer) @@ -446,10 +437,11 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { return } + params.Depositer = depositerAddr } if len(strProposalStatus) != 0 { - proposalStatus, err = gov.ProposalStatusFromString(strProposalStatus) + proposalStatus, err := gov.ProposalStatusFromString(strProposalStatus) if err != nil { w.WriteHeader(http.StatusBadRequest) err := errors.Errorf("'%s' is not a valid Proposal Status", strProposalStatus) @@ -457,41 +449,33 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { return } + params.ProposalStatus = proposalStatus } if len(strNumLatest) != 0 { - numLatest, ok = parseInt64OrReturnBadRequest(strNumLatest, w) + numLatest, ok := parseInt64OrReturnBadRequest(strNumLatest, w) if !ok { return } + params.NumLatestProposals = numLatest } - cliCtx := context.NewCLIContext().WithCodec(cdc) - - params := gov.QueryProposalsParams{ - Depositer: depositerAddr, - Voter: voterAddr, - ProposalStatus: proposalStatus, - NumLatestProposals: numLatest, - } - - res, err := cliCtx.QueryWithData("custom/gov/proposals", cdc.MustMarshalBinary(params)) + bz, err := cdc.MarshalJSON(params) if err != nil { - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) - return } - var matchingProposals []gov.Proposal - cdc.MustUnmarshalBinary(res, &matchingProposals) - output, err := wire.MarshalJSONIndent(cdc, matchingProposals) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + res, err := cliCtx.QueryWithData("custom/gov/proposals", bz) if err != nil { - w.WriteHeader(http.StatusBadRequest) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } - w.Write(output) + w.Write(res) } } diff --git a/x/gov/proposals.go b/x/gov/proposals.go index f05dabd08d06..c52ab1e8759d 100644 --- a/x/gov/proposals.go +++ b/x/gov/proposals.go @@ -110,6 +110,7 @@ type ProposalKind byte //nolint const ( + ProposalTypeNil ProposalKind = 0x00 ProposalTypeText ProposalKind = 0x01 ProposalTypeParameterChange ProposalKind = 0x02 ProposalTypeSoftwareUpgrade ProposalKind = 0x03 @@ -203,6 +204,7 @@ type ProposalStatus byte //nolint const ( + StatusNil ProposalStatus = 0x00 StatusDepositPeriod ProposalStatus = 0x01 StatusVotingPeriod ProposalStatus = 0x02 StatusPassed ProposalStatus = 0x03 @@ -220,6 +222,8 @@ func ProposalStatusFromString(str string) (ProposalStatus, error) { return StatusPassed, nil case "Rejected": return StatusRejected, nil + case "": + return StatusNil, nil default: return ProposalStatus(0xff), errors.Errorf("'%s' is not a valid proposal status", str) } diff --git a/x/gov/queryable.go b/x/gov/queryable.go index 28e32eb67548..e64d506d1e87 100644 --- a/x/gov/queryable.go +++ b/x/gov/queryable.go @@ -1,7 +1,10 @@ package gov import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" abci "github.com/tendermint/tendermint/abci/types" ) @@ -35,16 +38,21 @@ type QueryProposalParams struct { func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { var params QueryProposalParams - err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err2 != nil { - return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") + return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error())) } proposal := keeper.GetProposal(ctx, params.ProposalID) if proposal == nil { return []byte{}, ErrUnknownProposal(DefaultCodespace, params.ProposalID) } - return keeper.cdc.MustMarshalBinary(proposal), nil + + bz, err2 := wire.MarshalJSONIndent(keeper.cdc, proposal) + if err2 != nil { + panic("could not marshal result to JSON") + } + return bz, nil } // Params for query 'custom/gov/deposit' @@ -55,13 +63,17 @@ type QueryDepositParams struct { func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { var params QueryDepositParams - err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err2 != nil { - return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") + return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error())) } deposit, _ := keeper.GetDeposit(ctx, params.ProposalID, params.Depositer) - return keeper.cdc.MustMarshalBinary(deposit), nil + bz, err2 := wire.MarshalJSONIndent(keeper.cdc, deposit) + if err2 != nil { + panic("could not marshal result to JSON") + } + return bz, nil } // Params for query 'custom/gov/vote' @@ -72,13 +84,17 @@ type QueryVoteParams struct { func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { var params QueryVoteParams - err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err2 != nil { - return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") + return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error())) } vote, _ := keeper.GetVote(ctx, params.ProposalID, params.Voter) - return keeper.cdc.MustMarshalBinary(vote), nil + bz, err2 := wire.MarshalJSONIndent(keeper.cdc, vote) + if err2 != nil { + panic("could not marshal result to JSON") + } + return bz, nil } // Params for query 'custom/gov/deposits' @@ -88,9 +104,9 @@ type QueryDepositsParams struct { func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { var params QueryDepositParams - err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err2 != nil { - return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") + return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error())) } var deposits []Deposit @@ -101,7 +117,11 @@ func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper deposits = append(deposits, deposit) } - return keeper.cdc.MustMarshalBinary(deposits), nil + bz, err2 := wire.MarshalJSONIndent(keeper.cdc, deposits) + if err2 != nil { + panic("could not marshal result to JSON") + } + return bz, nil } // Params for query 'custom/gov/votes' @@ -111,9 +131,10 @@ type QueryVotesParams struct { func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { var params QueryVotesParams - err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) + if err2 != nil { - return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") + return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error())) } var votes []Vote @@ -124,7 +145,11 @@ func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke votes = append(votes, vote) } - return keeper.cdc.MustMarshalBinary(votes), nil + bz, err2 := wire.MarshalJSONIndent(keeper.cdc, votes) + if err2 != nil { + panic("could not marshal result to JSON") + } + return bz, nil } // Params for query 'custom/gov/proposals' @@ -137,14 +162,17 @@ type QueryProposalsParams struct { func queryProposals(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { var params QueryProposalsParams - err2 := keeper.cdc.UnmarshalBinary(req.Data, ¶ms) + err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err2 != nil { - return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") + return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error())) } proposals := keeper.GetProposalsFiltered(ctx, params.Voter, params.Depositer, params.ProposalStatus, params.NumLatestProposals) - bz := keeper.cdc.MustMarshalBinary(proposals) + bz, err2 := wire.MarshalJSONIndent(keeper.cdc, proposals) + if err2 != nil { + panic("could not marshal result to JSON") + } return bz, nil } @@ -157,9 +185,9 @@ func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke // TODO: Dependant on #1914 var proposalID int64 - err2 := keeper.cdc.UnmarshalBinary(req.Data, proposalID) + err2 := keeper.cdc.UnmarshalJSON(req.Data, proposalID) if err2 != nil { - return []byte{}, sdk.ErrUnknownRequest("incorrectly formatted request data") + return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error())) } proposal := keeper.GetProposal(ctx, proposalID) @@ -167,14 +195,19 @@ func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke return []byte{}, ErrUnknownProposal(DefaultCodespace, proposalID) } + var tallyResult TallyResult + if proposal.GetStatus() == StatusDepositPeriod { - return keeper.cdc.MustMarshalBinaryBare(EmptyTallyResult()), nil + tallyResult = EmptyTallyResult() + } else if proposal.GetStatus() == StatusPassed || proposal.GetStatus() == StatusRejected { + tallyResult = proposal.GetTallyResult() + } else { + _, tallyResult, _ = tally(ctx, keeper, proposal) } - if proposal.GetStatus() == StatusPassed || proposal.GetStatus() == StatusRejected { - return keeper.cdc.MustMarshalBinaryBare(proposal.GetTallyResult()), nil + bz, err2 := wire.MarshalJSONIndent(keeper.cdc, tallyResult) + if err2 != nil { + panic("could not marshal result to JSON") } - - _, tallyResult, _ := tally(ctx, keeper, proposal) - return keeper.cdc.MustMarshalBinaryBare(tallyResult), nil + return bz, nil } From 7f43d3b2900652a62f365bfad5dafb4b1bdd1e8f Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Wed, 22 Aug 2018 00:17:37 -0700 Subject: [PATCH 11/11] fixed GetLastProposalID function --- x/gov/keeper.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 19d842f1f368..e8dbbc4a7f09 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -167,12 +167,10 @@ func (keeper Keeper) setInitialProposalID(ctx sdk.Context, proposalID int64) sdk // Get the last used proposal ID func (keeper Keeper) GetLastProposalID(ctx sdk.Context) (proposalID int64) { - store := ctx.KVStore(keeper.storeKey) - bz := store.Get(KeyNextProposalID) - if bz == nil { + proposalID, err := keeper.peekCurrentProposalID(ctx) + if err != nil { return 0 } - keeper.cdc.MustUnmarshalBinary(bz, &proposalID) proposalID-- return }