From 13111176584b6a72bd00e4e5509b133387ed587f Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Sun, 5 Aug 2018 01:56:48 -0400 Subject: [PATCH] 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 081f723b5c..68676f7415 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 a96efa6b17..f79ffb3065 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 92e2988f24..258a095e8b 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 22283a652e..cf5481da8c 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())) + params := gov.QueryDepositParams{ + ProposalID: proposalID, + Depositer: depositerAddr, + } - return - } - - 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())) + params := gov.QueryVoteParams{ + Voter: voterAddr, + ProposalID: proposalID, + } - return - } - - 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 19ed97f69d..5a8b6bf249 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 c0e66d0bf7..13bdfd08dc 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") }