From 0e1d2eb64d50c89f291948c2e2ccc3ad68efb9d5 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 10:22:45 -0500 Subject: [PATCH 01/26] Cleanup gov handler and fix ID tags --- x/gov/handler.go | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/x/gov/handler.go b/x/gov/handler.go index 80d8bda40fb9..b357276561a2 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -25,16 +25,15 @@ func NewHandler(keeper Keeper) sdk.Handler { } func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitProposal) sdk.Result { - proposal := keeper.NewTextProposal(ctx, msg.Title, msg.Description, msg.ProposalType) + proposalID := proposal.GetProposalID() + proposalIDBytes := []byte(fmt.Sprintf("%d", proposalID)) - err, votingStarted := keeper.AddDeposit(ctx, proposal.GetProposalID(), msg.Proposer, msg.InitialDeposit) + err, votingStarted := keeper.AddDeposit(ctx, proposalID, msg.Proposer, msg.InitialDeposit) if err != nil { return err.Result() } - proposalIDBytes := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposal.GetProposalID()) - resTags := sdk.NewTags( tags.Proposer, []byte(msg.Proposer.String()), tags.ProposalID, proposalIDBytes, @@ -51,15 +50,12 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos } func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) sdk.Result { - err, votingStarted := keeper.AddDeposit(ctx, msg.ProposalID, msg.Depositor, msg.Amount) if err != nil { return err.Result() } - proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(msg.ProposalID) - - // TODO: Add tag for if voting period started + proposalIDBytes := []byte(fmt.Sprintf("%d", msg.ProposalID)) resTags := sdk.NewTags( tags.Depositor, []byte(msg.Depositor.String()), tags.ProposalID, proposalIDBytes, @@ -75,33 +71,28 @@ func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) sdk.Result } func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) sdk.Result { - err := keeper.AddVote(ctx, msg.ProposalID, msg.Voter, msg.Option) if err != nil { return err.Result() } - proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(msg.ProposalID) - - resTags := sdk.NewTags( - tags.Voter, []byte(msg.Voter.String()), - tags.ProposalID, proposalIDBytes, - ) return sdk.Result{ - Tags: resTags, + Tags: sdk.NewTags( + tags.Voter, []byte(msg.Voter.String()), + tags.ProposalID, []byte(fmt.Sprintf("%d", msg.ProposalID)), + ), } } // Called every block, process inflation, update validator set func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { - logger := ctx.Logger().With("module", "x/gov") - resTags = sdk.NewTags() inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) for ; inactiveIterator.Valid(); inactiveIterator.Next() { var proposalID uint64 + keeper.cdc.MustUnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID) inactiveProposal := keeper.GetProposal(ctx, proposalID) keeper.DeleteProposal(ctx, proposalID) @@ -119,11 +110,13 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { ), ) } + inactiveIterator.Close() activeIterator := keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) for ; activeIterator.Valid(); activeIterator.Next() { var proposalID uint64 + keeper.cdc.MustUnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID) activeProposal := keeper.GetProposal(ctx, proposalID) passes, tallyResults := tally(ctx, keeper, activeProposal) @@ -138,9 +131,9 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { activeProposal.SetStatus(StatusRejected) action = tags.ActionProposalRejected } + activeProposal.SetTallyResult(tallyResults) keeper.SetProposal(ctx, activeProposal) - keeper.RemoveFromActiveProposalQueue(ctx, activeProposal.GetVotingEndTime(), activeProposal.GetProposalID()) logger.Info(fmt.Sprintf("proposal %d (%s) tallied; passed: %v", @@ -149,6 +142,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { resTags = resTags.AppendTag(tags.Action, action) resTags = resTags.AppendTag(tags.ProposalID, []byte(string(proposalID))) } + activeIterator.Close() return resTags From 554e89580b1f896bce3a792acc834ab48d521877 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 10:29:34 -0500 Subject: [PATCH 02/26] Add action tags to vote and deposit handlers --- x/gov/handler.go | 4 +++- x/gov/tags/tags.go | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/x/gov/handler.go b/x/gov/handler.go index b357276561a2..fae867c1d59f 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -18,7 +18,7 @@ func NewHandler(keeper Keeper) sdk.Handler { case MsgVote: return handleMsgVote(ctx, keeper, msg) default: - errMsg := "Unrecognized gov msg type" + errMsg := fmt.Sprintf("Unrecognized gov msg type: %T", msg) return sdk.ErrUnknownRequest(errMsg).Result() } } @@ -57,6 +57,7 @@ func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) sdk.Result proposalIDBytes := []byte(fmt.Sprintf("%d", msg.ProposalID)) resTags := sdk.NewTags( + tags.Action, tags.ActionProposalDeposit, tags.Depositor, []byte(msg.Depositor.String()), tags.ProposalID, proposalIDBytes, ) @@ -78,6 +79,7 @@ func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) sdk.Result { return sdk.Result{ Tags: sdk.NewTags( + tags.Action, tags.ActionProposalVote, tags.Voter, []byte(msg.Voter.String()), tags.ProposalID, []byte(fmt.Sprintf("%d", msg.ProposalID)), ), diff --git a/x/gov/tags/tags.go b/x/gov/tags/tags.go index a58729dfed54..97c4f19a49aa 100644 --- a/x/gov/tags/tags.go +++ b/x/gov/tags/tags.go @@ -1,14 +1,16 @@ -// nolint package tags import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// Governance tags var ( ActionProposalDropped = []byte("proposal-dropped") ActionProposalPassed = []byte("proposal-passed") ActionProposalRejected = []byte("proposal-rejected") + ActionProposalVote = []byte("proposal-vote") + ActionProposalDeposit = []byte("proposal-deposit") Action = sdk.TagAction Proposer = "proposer" From 78667f484ac523cfbd36f6c4567963bc8479b131 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 11:36:38 -0500 Subject: [PATCH 03/26] Expose SearchTxs --- client/tx/search.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/tx/search.go b/client/tx/search.go index 422f4827668a..4f104008ad37 100644 --- a/client/tx/search.go +++ b/client/tx/search.go @@ -58,7 +58,7 @@ $ gaiacli query txs --tags ':&:' } cliCtx := context.NewCLIContext().WithCodec(cdc) - txs, err := searchTxs(cliCtx, cdc, tmTags) + txs, err := SearchTxs(cliCtx, cdc, tmTags) if err != nil { return err } @@ -89,7 +89,10 @@ $ gaiacli query txs --tags ':&:' return cmd } -func searchTxs(cliCtx context.CLIContext, cdc *codec.Codec, tags []string) ([]Info, error) { +// SearchTxs performs a search for transactions for a given set of tags via +// Tendermint RPC. It returns a slice of Info object containing txs and metadata. +// An error is returned if the query fails. +func SearchTxs(cliCtx context.CLIContext, cdc *codec.Codec, tags []string) ([]Info, error) { if len(tags) == 0 { return nil, errors.New("must declare at least one tag to search") } @@ -172,7 +175,7 @@ func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http. tags = append(tags, tag) } - txs, err = searchTxs(cliCtx, cdc, tags) + txs, err = SearchTxs(cliCtx, cdc, tags) if err != nil { utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return From e7faa8fa842702c05105ef68596aedea6d514513 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 11:36:51 -0500 Subject: [PATCH 04/26] Make MsgDeposit type a constant --- x/gov/msgs.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/x/gov/msgs.go b/x/gov/msgs.go index 6465b2a2d5dd..79005536b786 100644 --- a/x/gov/msgs.go +++ b/x/gov/msgs.go @@ -6,8 +6,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// name to idetify transaction types -const MsgRoute = "gov" +// Governance message types and routes +const ( + MsgRoute = "gov" + TypeMsgDeposit = "deposit" +) var _, _, _ sdk.Msg = MsgSubmitProposal{}, MsgDeposit{}, MsgVote{} @@ -100,7 +103,7 @@ func NewMsgDeposit(depositor sdk.AccAddress, proposalID uint64, amount sdk.Coins // Implements Msg. // nolint func (msg MsgDeposit) Route() string { return MsgRoute } -func (msg MsgDeposit) Type() string { return "deposit" } +func (msg MsgDeposit) Type() string { return TypeMsgDeposit } // Implements Msg. func (msg MsgDeposit) ValidateBasic() sdk.Error { From 7ee658e44794bd1ce0ac71c980480cb5624fed3f Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 11:37:05 -0500 Subject: [PATCH 05/26] Implement and use queryDepositsByTxQuery --- x/gov/client/rest/rest.go | 25 ++++++++++++++++--- x/gov/client/rest/utils.go | 50 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 x/gov/client/rest/utils.go diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 821da0cc7de6..e36ade34cae3 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -225,9 +225,7 @@ func queryProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha return } - params := gov.QueryProposalParams{ - ProposalID: proposalID, - } + params := gov.NewQueryProposalParams(proposalID) bz, err := cdc.MarshalJSON(params) if err != nil { @@ -263,7 +261,26 @@ func queryDepositsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha return } - res, err := cliCtx.QueryWithData("custom/gov/deposits", bz) + res, err := cliCtx.QueryWithData("custom/gov/proposal", bz) + if err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + var proposal gov.Proposal + if err := cdc.UnmarshalJSON(res, &proposal); err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + // For inactive proposals we must query the txs directly to get the deposits + // as they're no longer in state. + if proposal.GetStatus() != gov.StatusVotingPeriod { + queryDepositsByTxQuery(cdc, cliCtx, w, proposalID) + return + } + + res, err = cliCtx.QueryWithData("custom/gov/deposits", bz) if err != nil { utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return diff --git a/x/gov/client/rest/utils.go b/x/gov/client/rest/utils.go new file mode 100644 index 000000000000..5c4354d244e6 --- /dev/null +++ b/x/gov/client/rest/utils.go @@ -0,0 +1,50 @@ +package rest + +import ( + "fmt" + "net/http" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/client/utils" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/gov/tags" +) + +// queryDepositsByTxQuery will query for deposits via a direct txs tag query. It +// will fetch and build deposits directly from the returned txs and write the +// JSON response to the provided ResponseWriter. +// +// NOTE: SearchTxs is used to facilitate the txs query which does not currently +// support configurable pagination. +func queryDepositsByTxQuery(cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, proposalID uint64) { + tags := []string{ + fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalDeposit), + fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", proposalID))), + } + + infos, err := tx.SearchTxs(cliCtx, cdc, tags) + if err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + var deposits []gov.Deposit + + for _, info := range infos { + for _, msg := range info.Tx.GetMsgs() { + if msg.Type() == gov.TypeMsgDeposit { + depMsg := msg.(gov.MsgDeposit) + + deposits = append(deposits, gov.Deposit{ + Depositor: depMsg.Depositor, + ProposalID: proposalID, + Amount: depMsg.Amount, + }) + } + } + } + + utils.PostProcessResponse(w, cdc, deposits, cliCtx.Indent) +} From a56f5fc2f040bd1f082e742f54388002de401aca Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 11:48:53 -0500 Subject: [PATCH 06/26] Add TypeMsgVote constant --- x/gov/msgs.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/gov/msgs.go b/x/gov/msgs.go index 79005536b786..1d3891809beb 100644 --- a/x/gov/msgs.go +++ b/x/gov/msgs.go @@ -10,6 +10,7 @@ import ( const ( MsgRoute = "gov" TypeMsgDeposit = "deposit" + TypeMsgVote = "vote" ) var _, _, _ sdk.Msg = MsgSubmitProposal{}, MsgDeposit{}, MsgVote{} @@ -164,7 +165,7 @@ func NewMsgVote(voter sdk.AccAddress, proposalID uint64, option VoteOption) MsgV // Implements Msg. // nolint func (msg MsgVote) Route() string { return MsgRoute } -func (msg MsgVote) Type() string { return "vote" } +func (msg MsgVote) Type() string { return TypeMsgVote } // Implements Msg. func (msg MsgVote) ValidateBasic() sdk.Error { From ca78f0d234cd7aa1a0ba59aea305b876733702c1 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 11:49:13 -0500 Subject: [PATCH 07/26] Implement and use queryVotesByTxQuery --- x/gov/client/rest/rest.go | 21 +++++++++++++++++++- x/gov/client/rest/utils.go | 39 +++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index e36ade34cae3..26e6c144757c 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -446,7 +446,26 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) return } - res, err := cliCtx.QueryWithData("custom/gov/votes", bz) + res, err := cliCtx.QueryWithData("custom/gov/proposal", bz) + if err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + var proposal gov.Proposal + if err := cdc.UnmarshalJSON(res, &proposal); err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + // For inactive proposals we must query the txs directly to get the votes + // as they're no longer in state. + if proposal.GetStatus() != gov.StatusVotingPeriod { + queryVotesByTxQuery(cdc, cliCtx, w, proposalID) + return + } + + res, err = cliCtx.QueryWithData("custom/gov/votes", bz) if err != nil { utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return diff --git a/x/gov/client/rest/utils.go b/x/gov/client/rest/utils.go index 5c4354d244e6..b8cdbb262433 100644 --- a/x/gov/client/rest/utils.go +++ b/x/gov/client/rest/utils.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov/tags" ) -// queryDepositsByTxQuery will query for deposits via a direct txs tag query. It +// queryDepositsByTxQuery will query for deposits via a direct txs tags query. It // will fetch and build deposits directly from the returned txs and write the // JSON response to the provided ResponseWriter. // @@ -48,3 +48,40 @@ func queryDepositsByTxQuery(cdc *codec.Codec, cliCtx context.CLIContext, w http. utils.PostProcessResponse(w, cdc, deposits, cliCtx.Indent) } + +// queryVotesByTxQuery will query for votes via a direct txs tags query. It +// will fetch and build votes directly from the returned txs and write the +// JSON response to the provided ResponseWriter. +// +// NOTE: SearchTxs is used to facilitate the txs query which does not currently +// support configurable pagination. +func queryVotesByTxQuery(cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, proposalID uint64) { + tags := []string{ + fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalVote), + fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", proposalID))), + } + + infos, err := tx.SearchTxs(cliCtx, cdc, tags) + if err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + var votes []gov.Vote + + for _, info := range infos { + for _, msg := range info.Tx.GetMsgs() { + if msg.Type() == gov.TypeMsgVote { + voteMsg := msg.(gov.MsgVote) + + votes = append(votes, gov.Vote{ + Voter: voteMsg.Voter, + ProposalID: proposalID, + Option: voteMsg.Option, + }) + } + } + } + + utils.PostProcessResponse(w, cdc, votes, cliCtx.Indent) +} From 29fc73ae7de15ed40305347eaa92d75231d7541b Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 12:23:16 -0500 Subject: [PATCH 08/26] Fix data field in submit proposal --- client/lcd/lcd_test.go | 2 +- x/gov/handler.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 164edb0f39cf..b4bf38133157 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -501,7 +501,7 @@ func TestSubmitProposal(t *testing.T) { require.Equal(t, uint32(0), resultTx.DeliverTx.Code) var proposalID uint64 - cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID) + cdc.MustUnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID) // query proposal proposal := getProposal(t, port, proposalID) diff --git a/x/gov/handler.go b/x/gov/handler.go index fae867c1d59f..3fe9cd7a2b31 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -44,7 +44,7 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos } return sdk.Result{ - Data: proposalIDBytes, + Data: keeper.cdc.MustMarshalBinaryBare(proposalID), Tags: resTags, } } From 609ec8c0b517607d48d8295271ac0465fe7a068d Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 15:21:13 -0500 Subject: [PATCH 09/26] Fix tests and update proposal check --- client/lcd/lcd_test.go | 3 ++- x/gov/client/rest/rest.go | 19 ++++++++++++------- x/gov/handler.go | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index b4bf38133157..8e1926a1cccc 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -501,7 +501,7 @@ func TestSubmitProposal(t *testing.T) { require.Equal(t, uint32(0), resultTx.DeliverTx.Code) var proposalID uint64 - cdc.MustUnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID) + cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID) // query proposal proposal := getProposal(t, port, proposalID) @@ -686,6 +686,7 @@ func TestProposalsQuery(t *testing.T) { proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod) require.Len(t, proposals, 1) require.Equal(t, proposalID1, proposals[0].GetProposalID()) + // Only proposals #2 and #3 should be in Voting Period proposals = getProposalsFilterStatus(t, port, gov.StatusVotingPeriod) require.Len(t, proposals, 2) diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 26e6c144757c..de8ec21309fb 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -275,7 +275,8 @@ func queryDepositsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha // For inactive proposals we must query the txs directly to get the deposits // as they're no longer in state. - if proposal.GetStatus() != gov.StatusVotingPeriod { + propStatus := proposal.GetStatus() + if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { queryDepositsByTxQuery(cdc, cliCtx, w, proposalID) return } @@ -383,10 +384,8 @@ func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Handle return } - params := gov.QueryVoteParams{ - Voter: voterAddr, - ProposalID: proposalID, - } + params := gov.NewQueryVoteParams(proposalID, voterAddr) + bz, err := cdc.MarshalJSON(params) if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) @@ -400,7 +399,11 @@ func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Handle } var vote gov.Vote - cdc.UnmarshalJSON(res, &vote) + if err := cdc.UnmarshalJSON(res, &vote); err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + if vote.Empty() { bz, err := cdc.MarshalJSON(gov.QueryProposalParams{params.ProposalID}) if err != nil { @@ -417,6 +420,7 @@ func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Handle utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) return } + utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) } } @@ -460,7 +464,8 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) // For inactive proposals we must query the txs directly to get the votes // as they're no longer in state. - if proposal.GetStatus() != gov.StatusVotingPeriod { + propStatus := proposal.GetStatus() + if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { queryVotesByTxQuery(cdc, cliCtx, w, proposalID) return } diff --git a/x/gov/handler.go b/x/gov/handler.go index 3fe9cd7a2b31..538cbfeeb48e 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -44,7 +44,7 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos } return sdk.Result{ - Data: keeper.cdc.MustMarshalBinaryBare(proposalID), + Data: keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID), Tags: resTags, } } From 403b28a1ae2f14b01c00aab1cc93034fac8fafe2 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 15:49:20 -0500 Subject: [PATCH 10/26] Implement and use queryVoteByTxQuery --- x/gov/client/rest/rest.go | 23 ++++++++------- x/gov/client/rest/utils.go | 59 ++++++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index de8ec21309fb..7aee6515fa8e 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -277,7 +277,7 @@ func queryDepositsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha // as they're no longer in state. propStatus := proposal.GetStatus() if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { - queryDepositsByTxQuery(cdc, cliCtx, w, proposalID) + queryDepositsByTxQuery(cdc, cliCtx, w, params) return } @@ -399,25 +399,28 @@ func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Handle } var vote gov.Vote - if err := cdc.UnmarshalJSON(res, &vote); err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } + // TODO: We should check the error here but empty/non-existing votes will + // fail to unmarshal. + cdc.UnmarshalJSON(res, &vote) + // For an empty vote, either the proposal does not exist or is inactive in + // which case the vote would be removed from state and should be queried for + // directly via a txs query. if vote.Empty() { - bz, err := cdc.MarshalJSON(gov.QueryProposalParams{params.ProposalID}) + bz, err := cdc.MarshalJSON(gov.NewQueryProposalParams(proposalID)) if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } + res, err := cliCtx.QueryWithData("custom/gov/proposal", bz) if err != nil || len(res) == 0 { - err := errors.Errorf("proposalID [%d] does not exist", proposalID) + err := fmt.Errorf("proposalID %d does not exist", proposalID) utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) return } - err = errors.Errorf("voter [%s] did not deposit on proposalID [%d]", bechVoterAddr, proposalID) - utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) + + queryVoteByTxQuery(cdc, cliCtx, w, params) return } @@ -466,7 +469,7 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) // as they're no longer in state. propStatus := proposal.GetStatus() if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { - queryVotesByTxQuery(cdc, cliCtx, w, proposalID) + queryVotesByTxQuery(cdc, cliCtx, w, params) return } diff --git a/x/gov/client/rest/utils.go b/x/gov/client/rest/utils.go index b8cdbb262433..7c55e22970a3 100644 --- a/x/gov/client/rest/utils.go +++ b/x/gov/client/rest/utils.go @@ -18,10 +18,13 @@ import ( // // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. -func queryDepositsByTxQuery(cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, proposalID uint64) { +func queryDepositsByTxQuery( + cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, params gov.QueryProposalParams, +) { + tags := []string{ fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalDeposit), - fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", proposalID))), + fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), } infos, err := tx.SearchTxs(cliCtx, cdc, tags) @@ -39,7 +42,7 @@ func queryDepositsByTxQuery(cdc *codec.Codec, cliCtx context.CLIContext, w http. deposits = append(deposits, gov.Deposit{ Depositor: depMsg.Depositor, - ProposalID: proposalID, + ProposalID: params.ProposalID, Amount: depMsg.Amount, }) } @@ -55,10 +58,12 @@ func queryDepositsByTxQuery(cdc *codec.Codec, cliCtx context.CLIContext, w http. // // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. -func queryVotesByTxQuery(cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, proposalID uint64) { +func queryVotesByTxQuery( + cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, params gov.QueryProposalParams, +) { tags := []string{ fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalVote), - fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", proposalID))), + fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), } infos, err := tx.SearchTxs(cliCtx, cdc, tags) @@ -76,7 +81,7 @@ func queryVotesByTxQuery(cdc *codec.Codec, cliCtx context.CLIContext, w http.Res votes = append(votes, gov.Vote{ Voter: voteMsg.Voter, - ProposalID: proposalID, + ProposalID: params.ProposalID, Option: voteMsg.Option, }) } @@ -85,3 +90,45 @@ func queryVotesByTxQuery(cdc *codec.Codec, cliCtx context.CLIContext, w http.Res utils.PostProcessResponse(w, cdc, votes, cliCtx.Indent) } + +// queryVoteByTxQuery will query for a single vote via a direct txs tags query. +// +// NOTE: SearchTxs is used to facilitate the txs query which does not currently +// support configurable pagination. +func queryVoteByTxQuery( + cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, params gov.QueryVoteParams, +) { + + tags := []string{ + fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalVote), + fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + fmt.Sprintf("%s='%s'", tags.Voter, []byte(params.Voter.String())), + } + + infos, err := tx.SearchTxs(cliCtx, cdc, tags) + if err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + for _, info := range infos { + for _, msg := range info.Tx.GetMsgs() { + if msg.Type() == gov.TypeMsgVote { + voteMsg := msg.(gov.MsgVote) + + // there should only be a single vote under the given condition + vote := gov.Vote{ + Voter: voteMsg.Voter, + ProposalID: params.ProposalID, + Option: voteMsg.Option, + } + + utils.PostProcessResponse(w, cdc, vote, cliCtx.Indent) + return + } + } + } + + err = fmt.Errorf("voter '%s' did not vote on proposalID %d", params.Voter, params.ProposalID) + utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) +} From b424c76325eef0dcac8f037ac50f9e6b9b71a455 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 15:57:51 -0500 Subject: [PATCH 11/26] Implement and use queryDepositByTxQuery --- x/gov/client/rest/rest.go | 25 +++++++++++++------- x/gov/client/rest/utils.go | 47 ++++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 7aee6515fa8e..62f3acd3a238 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -320,10 +320,7 @@ func queryDepositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han return } - params := gov.QueryDepositParams{ - ProposalID: proposalID, - Depositor: depositorAddr, - } + params := gov.NewQueryDepositParams(proposalID, depositorAddr) bz, err := cdc.MarshalJSON(params) if err != nil { @@ -338,16 +335,28 @@ func queryDepositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han } var deposit gov.Deposit + // TODO: We should check the error here but empty/non-existing deposits will + // fail to unmarshal. cdc.UnmarshalJSON(res, &deposit) + + // For an empty deposit, either the proposal does not exist or is inactive in + // which case the deposit would be removed from state and should be queried + // for directly via a txs query. if deposit.Empty() { - res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinaryLengthPrefixed(gov.QueryProposalParams{params.ProposalID})) + bz, err := cdc.MarshalJSON(gov.NewQueryProposalParams(proposalID)) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + res, err := cliCtx.QueryWithData("custom/gov/proposal", bz) if err != nil || len(res) == 0 { - err := errors.Errorf("proposalID [%d] does not exist", proposalID) + err := fmt.Errorf("proposalID %d does not exist", proposalID) utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) return } - err = errors.Errorf("depositor [%s] did not deposit on proposalID [%d]", bechDepositorAddr, proposalID) - utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) + + queryDepositByTxQuery(cdc, cliCtx, w, params) return } diff --git a/x/gov/client/rest/utils.go b/x/gov/client/rest/utils.go index 7c55e22970a3..7c52e9746007 100644 --- a/x/gov/client/rest/utils.go +++ b/x/gov/client/rest/utils.go @@ -92,9 +92,6 @@ func queryVotesByTxQuery( } // queryVoteByTxQuery will query for a single vote via a direct txs tags query. -// -// NOTE: SearchTxs is used to facilitate the txs query which does not currently -// support configurable pagination. func queryVoteByTxQuery( cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, params gov.QueryVoteParams, ) { @@ -116,7 +113,7 @@ func queryVoteByTxQuery( if msg.Type() == gov.TypeMsgVote { voteMsg := msg.(gov.MsgVote) - // there should only be a single vote under the given condition + // there should only be a single vote under the given conditions vote := gov.Vote{ Voter: voteMsg.Voter, ProposalID: params.ProposalID, @@ -129,6 +126,46 @@ func queryVoteByTxQuery( } } - err = fmt.Errorf("voter '%s' did not vote on proposalID %d", params.Voter, params.ProposalID) + err = fmt.Errorf("address '%s' did not vote on proposalID %d", params.Voter, params.ProposalID) + utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) +} + +// queryDepositByTxQuery will query for a single deposit via a direct txs tags +// query. +func queryDepositByTxQuery( + cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, params gov.QueryDepositParams, +) { + + tags := []string{ + fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalDeposit), + fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), + fmt.Sprintf("%s='%s'", tags.Depositor, []byte(params.Depositor.String())), + } + + infos, err := tx.SearchTxs(cliCtx, cdc, tags) + if err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + for _, info := range infos { + for _, msg := range info.Tx.GetMsgs() { + if msg.Type() == gov.TypeMsgDeposit { + depMsg := msg.(gov.MsgDeposit) + + // there should only be a single deposit under the given conditions + deposit := gov.Deposit{ + Depositor: depMsg.Depositor, + ProposalID: params.ProposalID, + Amount: depMsg.Amount, + } + + utils.PostProcessResponse(w, cdc, deposit, cliCtx.Indent) + return + } + } + } + + err = fmt.Errorf("address '%s' did not deposit to proposalID %d", params.Depositor, params.ProposalID) utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) } From c457ca6dcebcb4c49de8fa72b39e360e4162417b Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 15:59:45 -0500 Subject: [PATCH 12/26] Replace some TODOs with FIXMEs --- x/gov/client/rest/rest.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 62f3acd3a238..5c686dcb2d3c 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -335,7 +335,7 @@ func queryDepositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han } var deposit gov.Deposit - // TODO: We should check the error here but empty/non-existing deposits will + // FIXME: We should check the error here but empty/non-existing deposits will // fail to unmarshal. cdc.UnmarshalJSON(res, &deposit) @@ -408,7 +408,7 @@ func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Handle } var vote gov.Vote - // TODO: We should check the error here but empty/non-existing votes will + // FIXME: We should check the error here but empty/non-existing votes will // fail to unmarshal. cdc.UnmarshalJSON(res, &vote) From 6fbbded0d502f4655a42629c595109ffdf28697e Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 16:02:36 -0500 Subject: [PATCH 13/26] Add pending log entry --- PENDING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PENDING.md b/PENDING.md index 9a5f51d8aa7a..814be4c72e28 100644 --- a/PENDING.md +++ b/PENDING.md @@ -32,6 +32,9 @@ FEATURES IMPROVEMENTS * Gaia REST API (`gaiacli advanced rest-server`) + * \#3091 Update deposit and vote endpoints to perform a direct txs query + when a given proposal is inactive and thus having votes and deposits removed + from state. * Gaia CLI (`gaiacli`) From b998c36fb72da6d30a05fb9ce8c6f88ace85533c Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 16:59:31 -0500 Subject: [PATCH 14/26] Move and update query tx utils to different package so CLI can use them --- x/gov/client/rest/rest.go | 31 +++++--- .../client/{rest/utils.go => utils/query.go} | 75 +++++++++---------- 2 files changed, 53 insertions(+), 53 deletions(-) rename x/gov/client/{rest/utils.go => utils/query.go} (66%) diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 5c686dcb2d3c..0c9087aadd33 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov" + gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" "github.com/gorilla/mux" "github.com/pkg/errors" @@ -277,11 +278,11 @@ func queryDepositsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha // as they're no longer in state. propStatus := proposal.GetStatus() if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { - queryDepositsByTxQuery(cdc, cliCtx, w, params) - return + res, err = gcutils.QueryDepositsByTxQuery(cdc, cliCtx, params) + } else { + res, err = cliCtx.QueryWithData("custom/gov/deposits", bz) } - res, err = cliCtx.QueryWithData("custom/gov/deposits", bz) if err != nil { utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return @@ -349,15 +350,18 @@ func queryDepositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han return } - res, err := cliCtx.QueryWithData("custom/gov/proposal", bz) + res, err = cliCtx.QueryWithData("custom/gov/proposal", bz) if err != nil || len(res) == 0 { err := fmt.Errorf("proposalID %d does not exist", proposalID) utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) return } - queryDepositByTxQuery(cdc, cliCtx, w, params) - return + res, err = gcutils.QueryDepositByTxQuery(cdc, cliCtx, params) + if err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } } utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) @@ -422,15 +426,18 @@ func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Handle return } - res, err := cliCtx.QueryWithData("custom/gov/proposal", bz) + res, err = cliCtx.QueryWithData("custom/gov/proposal", bz) if err != nil || len(res) == 0 { err := fmt.Errorf("proposalID %d does not exist", proposalID) utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) return } - queryVoteByTxQuery(cdc, cliCtx, w, params) - return + res, err = gcutils.QueryVoteByTxQuery(cdc, cliCtx, params) + if err != nil { + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } } utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) @@ -478,11 +485,11 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) // as they're no longer in state. propStatus := proposal.GetStatus() if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { - queryVotesByTxQuery(cdc, cliCtx, w, params) - return + res, err = gcutils.QueryVotesByTxQuery(cdc, cliCtx, params) + } else { + res, err = cliCtx.QueryWithData("custom/gov/votes", bz) } - res, err = cliCtx.QueryWithData("custom/gov/votes", bz) if err != nil { utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return diff --git a/x/gov/client/rest/utils.go b/x/gov/client/utils/query.go similarity index 66% rename from x/gov/client/rest/utils.go rename to x/gov/client/utils/query.go index 7c52e9746007..b394f3a22ec4 100644 --- a/x/gov/client/rest/utils.go +++ b/x/gov/client/utils/query.go @@ -1,26 +1,24 @@ -package rest +package utils import ( "fmt" - "net/http" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/gov/tags" ) -// queryDepositsByTxQuery will query for deposits via a direct txs tags query. It -// will fetch and build deposits directly from the returned txs and write the -// JSON response to the provided ResponseWriter. +// QueryDepositsByTxQuery will query for deposits via a direct txs tags query. It +// will fetch and build deposits directly from the returned txs and return a +// JSON marshalled result or any error that occurred. // // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. -func queryDepositsByTxQuery( - cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, params gov.QueryProposalParams, -) { +func QueryDepositsByTxQuery( + cdc *codec.Codec, cliCtx context.CLIContext, params gov.QueryProposalParams, +) ([]byte, error) { tags := []string{ fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalDeposit), @@ -29,8 +27,7 @@ func queryDepositsByTxQuery( infos, err := tx.SearchTxs(cliCtx, cdc, tags) if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return + return nil, err } var deposits []gov.Deposit @@ -49,18 +46,19 @@ func queryDepositsByTxQuery( } } - utils.PostProcessResponse(w, cdc, deposits, cliCtx.Indent) + return cdc.MarshalJSON(deposits) } -// queryVotesByTxQuery will query for votes via a direct txs tags query. It -// will fetch and build votes directly from the returned txs and write the -// JSON response to the provided ResponseWriter. +// QueryVotesByTxQuery will query for votes via a direct txs tags query. It +// will fetch and build votes directly from the returned txs and return a JSON +// marshalled result or any error that occurred. // // NOTE: SearchTxs is used to facilitate the txs query which does not currently // support configurable pagination. -func queryVotesByTxQuery( - cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, params gov.QueryProposalParams, -) { +func QueryVotesByTxQuery( + cdc *codec.Codec, cliCtx context.CLIContext, params gov.QueryProposalParams, +) ([]byte, error) { + tags := []string{ fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalVote), fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))), @@ -68,8 +66,7 @@ func queryVotesByTxQuery( infos, err := tx.SearchTxs(cliCtx, cdc, tags) if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return + return nil, err } var votes []gov.Vote @@ -88,13 +85,13 @@ func queryVotesByTxQuery( } } - utils.PostProcessResponse(w, cdc, votes, cliCtx.Indent) + return cdc.MarshalJSON(votes) } -// queryVoteByTxQuery will query for a single vote via a direct txs tags query. -func queryVoteByTxQuery( - cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, params gov.QueryVoteParams, -) { +// QueryVoteByTxQuery will query for a single vote via a direct txs tags query. +func QueryVoteByTxQuery( + cdc *codec.Codec, cliCtx context.CLIContext, params gov.QueryVoteParams, +) ([]byte, error) { tags := []string{ fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalVote), @@ -104,8 +101,7 @@ func queryVoteByTxQuery( infos, err := tx.SearchTxs(cliCtx, cdc, tags) if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return + return nil, err } for _, info := range infos { @@ -113,28 +109,27 @@ func queryVoteByTxQuery( if msg.Type() == gov.TypeMsgVote { voteMsg := msg.(gov.MsgVote) - // there should only be a single vote under the given conditions vote := gov.Vote{ Voter: voteMsg.Voter, ProposalID: params.ProposalID, Option: voteMsg.Option, } - utils.PostProcessResponse(w, cdc, vote, cliCtx.Indent) - return + // there should only be a single vote under the given conditions + return cdc.MarshalJSON(vote) } } } err = fmt.Errorf("address '%s' did not vote on proposalID %d", params.Voter, params.ProposalID) - utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) + return nil, err } -// queryDepositByTxQuery will query for a single deposit via a direct txs tags +// QueryDepositByTxQuery will query for a single deposit via a direct txs tags // query. -func queryDepositByTxQuery( - cdc *codec.Codec, cliCtx context.CLIContext, w http.ResponseWriter, params gov.QueryDepositParams, -) { +func QueryDepositByTxQuery( + cdc *codec.Codec, cliCtx context.CLIContext, params gov.QueryDepositParams, +) ([]byte, error) { tags := []string{ fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalDeposit), @@ -144,8 +139,7 @@ func queryDepositByTxQuery( infos, err := tx.SearchTxs(cliCtx, cdc, tags) if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return + return nil, err } for _, info := range infos { @@ -153,19 +147,18 @@ func queryDepositByTxQuery( if msg.Type() == gov.TypeMsgDeposit { depMsg := msg.(gov.MsgDeposit) - // there should only be a single deposit under the given conditions deposit := gov.Deposit{ Depositor: depMsg.Depositor, ProposalID: params.ProposalID, Amount: depMsg.Amount, } - utils.PostProcessResponse(w, cdc, deposit, cliCtx.Indent) - return + // there should only be a single deposit under the given conditions + return cdc.MarshalJSON(deposit) } } } err = fmt.Errorf("address '%s' did not deposit to proposalID %d", params.Depositor, params.ProposalID) - utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) + return nil, err } From b1fcc809fa079349430ce18ced4be9e1bf860afe Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 17:04:48 -0500 Subject: [PATCH 15/26] Update votes CLI command --- x/gov/client/cli/query.go | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index 06dabfcddfd5..861ef5f5177f 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov" - govClientUtils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" + gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" ) // GetCmdQueryProposal implements the query proposal command. @@ -106,7 +106,7 @@ $ gaiacli query gov proposals --status (DepositPeriod|VotingPeriod|Passed|Reject } if len(strProposalStatus) != 0 { - proposalStatus, err := gov.ProposalStatusFromString(govClientUtils.NormalizeProposalStatus(strProposalStatus)) + proposalStatus, err := gov.ProposalStatusFromString(gcutils.NormalizeProposalStatus(strProposalStatus)) if err != nil { return err } @@ -213,8 +213,9 @@ func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(1), Short: "Query votes on a proposal", Long: strings.TrimSpace(` -Query vote details for a single proposal. You can find the proposal-id by running gaiacli query gov proposals: +Query vote details for a single proposal by its identifier. +Example: $ gaiacli query gov votes 1 `), RunE: func(cmd *cobra.Command, args []string) error { @@ -226,21 +227,30 @@ $ gaiacli query gov votes 1 return fmt.Errorf("proposal-id %s not a valid int, please input a valid proposal-id", args[0]) } + params := gov.NewQueryProposalParams(proposalID) + bz, err := cdc.MarshalJSON(params) + if err != nil { + return err + } + // check to see if the proposal is in the store - _, err = queryProposal(proposalID, cliCtx, cdc, queryRoute) + res, err := queryProposal(proposalID, cliCtx, cdc, queryRoute) if err != nil { return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } - // Construct query - params := gov.NewQueryProposalParams(proposalID) - bz, err := cdc.MarshalJSON(params) - if err != nil { + var proposal gov.Proposal + if err := cdc.UnmarshalJSON(res, &proposal); err != nil { return err } - // Query store - res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/votes", queryRoute), bz) + propStatus := proposal.GetStatus() + if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { + res, err = gcutils.QueryVotesByTxQuery(cdc, cliCtx, params) + } else { + res, err = cliCtx.QueryWithData(fmt.Sprintf("custom/%s/votes", queryRoute), bz) + } + if err != nil { return err } From 2ffca9ce7187a7b532a3e0652df69a4372e3b5ab Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 17:06:39 -0500 Subject: [PATCH 16/26] Update deposits CLI command --- x/gov/client/cli/query.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index 861ef5f5177f..31ddb8411aaa 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -337,21 +337,30 @@ $ gaiacli query gov deposits 1 return fmt.Errorf("proposal-id %s not a valid uint, please input a valid proposal-id", args[0]) } + params := gov.NewQueryProposalParams(proposalID) + bz, err := cdc.MarshalJSON(params) + if err != nil { + return err + } + // check to see if the proposal is in the store - _, err = queryProposal(proposalID, cliCtx, cdc, queryRoute) + res, err := queryProposal(proposalID, cliCtx, cdc, queryRoute) if err != nil { return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } - // Construct query - params := gov.NewQueryProposalParams(proposalID) - bz, err := cdc.MarshalJSON(params) - if err != nil { + var proposal gov.Proposal + if err := cdc.UnmarshalJSON(res, &proposal); err != nil { return err } - // Query store - res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/deposits", queryRoute), bz) + propStatus := proposal.GetStatus() + if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { + res, err = gcutils.QueryVotesByTxQuery(cdc, cliCtx, params) + } else { + res, err = cliCtx.QueryWithData(fmt.Sprintf("custom/%s/deposits", queryRoute), bz) + } + if err != nil { return err } From 191d201246fcd31d05a1b17e0fbe77e3d81e6f34 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 17:35:22 -0500 Subject: [PATCH 17/26] Update deposit CLI command --- x/gov/client/cli/query.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index 31ddb8411aaa..a2cc9818ac5e 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -271,8 +271,9 @@ func GetCmdQueryDeposit(queryRoute string, cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(2), Short: "Query details of a deposit", Long: strings.TrimSpace(` -Query details for a single proposal deposit on a proposal. You can find the proposal-id by running gaiacli query gov proposals: +Query details for a single proposal deposit on a proposal by its identifier. +Example: $ gaiacli query gov deposit 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk `), RunE: func(cmd *cobra.Command, args []string) error { @@ -290,25 +291,34 @@ $ gaiacli query gov deposit 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } - // Get the depositer address depositorAddr, err := sdk.AccAddressFromBech32(args[1]) if err != nil { return err } - // Construct query params := gov.NewQueryDepositParams(proposalID, depositorAddr) bz, err := cdc.MarshalJSON(params) if err != nil { return err } - // Query store res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/deposit", queryRoute), bz) if err != nil { return err } + var deposit gov.Deposit + // FIXME: We should check the error here but empty/non-existing deposits will + // fail to unmarshal. + cdc.UnmarshalJSON(res, &deposit) + + if deposit.Empty() { + res, err = gcutils.QueryDepositByTxQuery(cdc, cliCtx, params) + if err != nil { + return err + } + } + fmt.Println(string(res)) return nil }, From bacf1213223d356e675baefc031734a5702452a8 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 17:38:42 -0500 Subject: [PATCH 18/26] Update vote CLI command --- x/gov/client/cli/query.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index a2cc9818ac5e..424dac26f44c 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -160,8 +160,9 @@ func GetCmdQueryVote(queryRoute string, cdc *codec.Codec) *cobra.Command { Args: cobra.ExactArgs(2), Short: "Query details of a single vote", Long: strings.TrimSpace(` -Query details for a single vote on a proposal. You can find the proposal-id by running gaiacli query gov proposals: +Query details for a single vote on a proposal given its identifier. +Example: $ gaiacli query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk `), RunE: func(cmd *cobra.Command, args []string) error { @@ -179,25 +180,34 @@ $ gaiacli query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } - // get voter address voterAddr, err := sdk.AccAddressFromBech32(args[1]) if err != nil { return err } - // Construct query params := gov.NewQueryVoteParams(proposalID, voterAddr) bz, err := cdc.MarshalJSON(params) if err != nil { return err } - // Query store res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/vote", queryRoute), bz) if err != nil { return err } + var vote gov.Vote + // FIXME: We should check the error here but empty/non-existing votes will + // fail to unmarshal. + cdc.UnmarshalJSON(res, &vote) + + if vote.Empty() { + res, err = gcutils.QueryVoteByTxQuery(cdc, cliCtx, params) + if err != nil { + return err + } + } + fmt.Println(string(res)) return nil }, From 249e7a5ae5409df2b5d7fef3b00ebb7e886abc10 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 17:39:24 -0500 Subject: [PATCH 19/26] Update pending log --- PENDING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PENDING.md b/PENDING.md index 814be4c72e28..557572f07cd4 100644 --- a/PENDING.md +++ b/PENDING.md @@ -37,6 +37,9 @@ IMPROVEMENTS from state. * Gaia CLI (`gaiacli`) + * \#3091 Update deposit and vote CLI commands to perform a direct txs query + when a given proposal is inactive and thus having votes and deposits removed + from state. * Gaia * [\#3021](https://github.com/cosmos/cosmos-sdk/pull/3021) Add `--gentx-dir` to `gaiad collect-gentxs` to specify a directory from which collect and load gentxs. From 0a4cf62115c174902d80f5c473b3337192dc5304 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 17:51:13 -0500 Subject: [PATCH 20/26] Support indentation --- x/gov/client/utils/query.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/x/gov/client/utils/query.go b/x/gov/client/utils/query.go index b394f3a22ec4..fdae6f3b059f 100644 --- a/x/gov/client/utils/query.go +++ b/x/gov/client/utils/query.go @@ -46,6 +46,10 @@ func QueryDepositsByTxQuery( } } + if cliCtx.Indent { + return cdc.MarshalJSONIndent(deposits, "", " ") + } + return cdc.MarshalJSON(deposits) } @@ -85,6 +89,10 @@ func QueryVotesByTxQuery( } } + if cliCtx.Indent { + return cdc.MarshalJSONIndent(votes, "", " ") + } + return cdc.MarshalJSON(votes) } @@ -106,6 +114,7 @@ func QueryVoteByTxQuery( for _, info := range infos { for _, msg := range info.Tx.GetMsgs() { + // there should only be a single vote under the given conditions if msg.Type() == gov.TypeMsgVote { voteMsg := msg.(gov.MsgVote) @@ -115,7 +124,10 @@ func QueryVoteByTxQuery( Option: voteMsg.Option, } - // there should only be a single vote under the given conditions + if cliCtx.Indent { + return cdc.MarshalJSONIndent(vote, "", " ") + } + return cdc.MarshalJSON(vote) } } @@ -144,6 +156,7 @@ func QueryDepositByTxQuery( for _, info := range infos { for _, msg := range info.Tx.GetMsgs() { + // there should only be a single deposit under the given conditions if msg.Type() == gov.TypeMsgDeposit { depMsg := msg.(gov.MsgDeposit) @@ -153,7 +166,10 @@ func QueryDepositByTxQuery( Amount: depMsg.Amount, } - // there should only be a single deposit under the given conditions + if cliCtx.Indent { + return cdc.MarshalJSONIndent(deposit, "", " ") + } + return cdc.MarshalJSON(deposit) } } From 8087ce66019a01933c486a21e90522c8da99e0f3 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 18:09:04 -0500 Subject: [PATCH 21/26] Add tag to proposal creation --- x/gov/handler.go | 1 + x/gov/tags/tags.go | 1 + 2 files changed, 2 insertions(+) diff --git a/x/gov/handler.go b/x/gov/handler.go index 538cbfeeb48e..24d6d205ae54 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -35,6 +35,7 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos } resTags := sdk.NewTags( + tags.Action, tags.ActionProposalCreated, tags.Proposer, []byte(msg.Proposer.String()), tags.ProposalID, proposalIDBytes, ) diff --git a/x/gov/tags/tags.go b/x/gov/tags/tags.go index 97c4f19a49aa..676a53922f8a 100644 --- a/x/gov/tags/tags.go +++ b/x/gov/tags/tags.go @@ -9,6 +9,7 @@ var ( ActionProposalDropped = []byte("proposal-dropped") ActionProposalPassed = []byte("proposal-passed") ActionProposalRejected = []byte("proposal-rejected") + ActionProposalCreated = []byte("proposal-created") ActionProposalVote = []byte("proposal-vote") ActionProposalDeposit = []byte("proposal-deposit") From cbf332ba757c6cc95d0deaf21445b0e8e28c4680 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 18:56:24 -0500 Subject: [PATCH 22/26] Remove FIXMEs --- x/gov/client/cli/query.go | 4 ---- x/gov/client/rest/rest.go | 4 ---- 2 files changed, 8 deletions(-) diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index 424dac26f44c..c24d106ee9f9 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -197,8 +197,6 @@ $ gaiacli query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk } var vote gov.Vote - // FIXME: We should check the error here but empty/non-existing votes will - // fail to unmarshal. cdc.UnmarshalJSON(res, &vote) if vote.Empty() { @@ -318,8 +316,6 @@ $ gaiacli query gov deposit 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk } var deposit gov.Deposit - // FIXME: We should check the error here but empty/non-existing deposits will - // fail to unmarshal. cdc.UnmarshalJSON(res, &deposit) if deposit.Empty() { diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 0c9087aadd33..1b51566f8442 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -336,8 +336,6 @@ func queryDepositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han } var deposit gov.Deposit - // FIXME: We should check the error here but empty/non-existing deposits will - // fail to unmarshal. cdc.UnmarshalJSON(res, &deposit) // For an empty deposit, either the proposal does not exist or is inactive in @@ -412,8 +410,6 @@ func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Handle } var vote gov.Vote - // FIXME: We should check the error here but empty/non-existing votes will - // fail to unmarshal. cdc.UnmarshalJSON(res, &vote) // For an empty vote, either the proposal does not exist or is inactive in From 2e4a2357ca4627046dcf48f4244f13ac4696b0eb Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 12 Dec 2018 23:23:29 -0500 Subject: [PATCH 23/26] Fix query deposits cmd --- x/gov/client/cli/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index c24d106ee9f9..61cc00242891 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -372,7 +372,7 @@ $ gaiacli query gov deposits 1 propStatus := proposal.GetStatus() if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { - res, err = gcutils.QueryVotesByTxQuery(cdc, cliCtx, params) + res, err = gcutils.QueryDepositsByTxQuery(cdc, cliCtx, params) } else { res, err = cliCtx.QueryWithData(fmt.Sprintf("custom/%s/deposits", queryRoute), bz) } From 9b813fcf0b5158b618b83387abbf72b4f11bbd6e Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 13 Dec 2018 08:42:58 -0500 Subject: [PATCH 24/26] Update pending log --- PENDING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PENDING.md b/PENDING.md index 557572f07cd4..3da2554fc79a 100644 --- a/PENDING.md +++ b/PENDING.md @@ -32,12 +32,12 @@ FEATURES IMPROVEMENTS * Gaia REST API (`gaiacli advanced rest-server`) - * \#3091 Update deposit and vote endpoints to perform a direct txs query + * \#2879, \#2880 Update deposit and vote endpoints to perform a direct txs query when a given proposal is inactive and thus having votes and deposits removed from state. * Gaia CLI (`gaiacli`) - * \#3091 Update deposit and vote CLI commands to perform a direct txs query + * \#2879, \#2880 Update deposit and vote CLI commands to perform a direct txs query when a given proposal is inactive and thus having votes and deposits removed from state. From fc0c689b2a360248a9d5dea2a01519333b71907c Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 13 Dec 2018 09:31:12 -0500 Subject: [PATCH 25/26] Update tags and consts --- x/gov/handler.go | 2 +- x/gov/msgs.go | 9 +++++---- x/gov/tags/tags.go | 12 ++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/x/gov/handler.go b/x/gov/handler.go index 24d6d205ae54..4c2d298ff37c 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -35,7 +35,7 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos } resTags := sdk.NewTags( - tags.Action, tags.ActionProposalCreated, + tags.Action, tags.ActionProposalSubmitted, tags.Proposer, []byte(msg.Proposer.String()), tags.ProposalID, proposalIDBytes, ) diff --git a/x/gov/msgs.go b/x/gov/msgs.go index 1d3891809beb..12f5fd33af26 100644 --- a/x/gov/msgs.go +++ b/x/gov/msgs.go @@ -8,9 +8,10 @@ import ( // Governance message types and routes const ( - MsgRoute = "gov" - TypeMsgDeposit = "deposit" - TypeMsgVote = "vote" + MsgRoute = "gov" + TypeMsgDeposit = "deposit" + TypeMsgVote = "vote" + TypeMsgSubmitProposal = "submit_proposal" ) var _, _, _ sdk.Msg = MsgSubmitProposal{}, MsgDeposit{}, MsgVote{} @@ -37,7 +38,7 @@ func NewMsgSubmitProposal(title string, description string, proposalType Proposa //nolint func (msg MsgSubmitProposal) Route() string { return MsgRoute } -func (msg MsgSubmitProposal) Type() string { return "submit_proposal" } +func (msg MsgSubmitProposal) Type() string { return TypeMsgSubmitProposal } // Implements Msg. func (msg MsgSubmitProposal) ValidateBasic() sdk.Error { diff --git a/x/gov/tags/tags.go b/x/gov/tags/tags.go index 676a53922f8a..d1cb4bf2f880 100644 --- a/x/gov/tags/tags.go +++ b/x/gov/tags/tags.go @@ -6,12 +6,12 @@ import ( // Governance tags var ( - ActionProposalDropped = []byte("proposal-dropped") - ActionProposalPassed = []byte("proposal-passed") - ActionProposalRejected = []byte("proposal-rejected") - ActionProposalCreated = []byte("proposal-created") - ActionProposalVote = []byte("proposal-vote") - ActionProposalDeposit = []byte("proposal-deposit") + ActionProposalDropped = []byte("proposal-dropped") + ActionProposalPassed = []byte("proposal-passed") + ActionProposalRejected = []byte("proposal-rejected") + ActionProposalSubmitted = []byte("proposal-Submitted") + ActionProposalVote = []byte("proposal-vote") + ActionProposalDeposit = []byte("proposal-deposit") Action = sdk.TagAction Proposer = "proposer" From 6947793236590bac1d38ef5a98cc43b3f5840113 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 13 Dec 2018 09:36:01 -0500 Subject: [PATCH 26/26] Lowercase submitted --- x/gov/tags/tags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/gov/tags/tags.go b/x/gov/tags/tags.go index d1cb4bf2f880..33986f9720d3 100644 --- a/x/gov/tags/tags.go +++ b/x/gov/tags/tags.go @@ -9,7 +9,7 @@ var ( ActionProposalDropped = []byte("proposal-dropped") ActionProposalPassed = []byte("proposal-passed") ActionProposalRejected = []byte("proposal-rejected") - ActionProposalSubmitted = []byte("proposal-Submitted") + ActionProposalSubmitted = []byte("proposal-submitted") ActionProposalVote = []byte("proposal-vote") ActionProposalDeposit = []byte("proposal-deposit")