Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: Implement Proposal Proposer client interfaces #3184

Merged
merged 3 commits into from
Dec 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ FEATURES
* Gaia REST API (`gaiacli advanced rest-server`)
* [\#3067](https://github.com/cosmos/cosmos-sdk/issues/3067) Add support for fees on transactions
* [\#3069](https://github.com/cosmos/cosmos-sdk/pull/3069) Add a custom memo on transactions
* [\#3027](https://github.com/cosmos/cosmos-sdk/issues/3027) Implement
`/gov/proposals/{proposalID}/proposer` to query for a proposal's proposer.

* Gaia CLI (`gaiacli`)
* \#2399 Implement `params` command to query slashing parameters.
* [\#3027](https://github.com/cosmos/cosmos-sdk/issues/3027) Implement
`query gov proposer [proposal-id]` to query for a proposal's proposer.

* Gaia
* [\#2182] [x/stake] Added querier for querying a single redelegation
Expand Down
7 changes: 3 additions & 4 deletions client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,10 +553,9 @@ func TestSubmitProposal(t *testing.T) {
proposal := getProposal(t, port, proposalID)
require.Equal(t, "Test", proposal.GetTitle())

// query tx
txs := getTransactions(t, port, fmt.Sprintf("action=submit_proposal&proposer=%s", addr))
require.Len(t, txs, 1)
require.Equal(t, resultTx.Height, txs[0].Height)
proposer := getProposer(t, port, proposalID)
require.Equal(t, addr.String(), proposer.Proposer)
require.Equal(t, proposalID, proposer.ProposalID)
}

func TestDeposit(t *testing.T) {
Expand Down
29 changes: 29 additions & 0 deletions client/lcd/swagger-ui/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,28 @@ paths:
description: Invalid proposal id
500:
description: Internal Server Error
/gov/proposals/{proposalId}/proposer:
get:
summary: Query proposer
description: Query for the proposer for a proposal
produces:
- application/json
tags:
- ICS22
parameters:
- type: string
name: proposalId
required: true
in: path
responses:
200:
description: OK
schema:
$ref: "#/definitions/Proposer"
400:
description: Invalid proposal ID
500:
description: Internal Server Error
/gov/proposals/{proposalId}/deposits:
get:
summary: Query deposits
Expand Down Expand Up @@ -2268,6 +2290,13 @@ definitions:
$ref: "#/definitions/Coin"
voting_start_time:
type: string
Proposer:
type: object
properties:
proposal_id:
type: integer
proposer:
type: string
Deposit:
type: object
properties:
Expand Down
18 changes: 16 additions & 2 deletions client/lcd/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ import (
"strings"
"testing"

"github.com/tendermint/tendermint/crypto/secp256k1"
ctypes "github.com/tendermint/tendermint/rpc/core/types"

cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/tendermint/tendermint/crypto/secp256k1"
ctypes "github.com/tendermint/tendermint/rpc/core/types"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
Expand All @@ -35,6 +36,7 @@ import (
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils"
"github.com/cosmos/cosmos-sdk/x/stake"

"github.com/spf13/viper"
Expand Down Expand Up @@ -1249,6 +1251,18 @@ func getVote(t *testing.T, port string, proposalID uint64, voterAddr sdk.AccAddr
return vote
}

// GET /gov/proposals/{proposalId}/proposer
func getProposer(t *testing.T, port string, proposalID uint64) gcutils.Proposer {
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/proposer", proposalID), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)

var proposer gcutils.Proposer
err := cdc.UnmarshalJSON([]byte(body), &proposer)

require.Nil(t, err)
return proposer
}

// GET /gov/parameters/deposit Query governance deposit parameters
func getDepositParam(t *testing.T, port string) gov.DepositParams {
res, body := Request(t, port, "GET", "/gov/parameters/deposit", nil)
Expand Down
6 changes: 6 additions & 0 deletions docs/gaia/gaiacli.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,12 @@ gaiacli query gov proposals

You can also query proposals filtered by `voter` or `depositor` by using the corresponding flags.

To query for the proposer of a given governance proposal:

```bash
gaiacli query gov proposer <proposal_id>
```

#### Increase deposit

In order for a proposal to be broadcasted to the network, the amount deposited must be above a `minDeposit` value (default: `10 steak`). If the proposal you previously created didn't meet this requirement, you can still increase the total amount deposited to activate it. Once the minimum deposit is reached, the proposal enters voting period:
Expand Down
28 changes: 28 additions & 0 deletions x/gov/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,3 +458,31 @@ func GetCmdQueryParams(queryRoute string, cdc *codec.Codec) *cobra.Command {

return cmd
}

// GetCmdQueryProposer implements the query proposer command.
func GetCmdQueryProposer(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "proposer [proposal-id]",
Args: cobra.ExactArgs(1),
Short: "Query the proposer of a governance proposal",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)

// validate that the proposalID is a uint
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("proposal-id %s is not a valid uint", args[0])
}

res, err := gcutils.QueryProposerByTxQuery(cdc, cliCtx, proposalID)
if err != nil {
return err
}

fmt.Println(string(res))
return nil
},
}

return cmd
}
1 change: 1 addition & 0 deletions x/gov/client/module_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func (mc ModuleClient) GetQueryCmd() *cobra.Command {
govCli.GetCmdQueryVote(mc.storeKey, mc.cdc),
govCli.GetCmdQueryVotes(mc.storeKey, mc.cdc),
govCli.GetCmdQueryParams(mc.storeKey, mc.cdc),
govCli.GetCmdQueryProposer(mc.storeKey, mc.cdc),
govCli.GetCmdQueryDeposit(mc.storeKey, mc.cdc),
govCli.GetCmdQueryDeposits(mc.storeKey, mc.cdc),
govCli.GetCmdQueryTally(mc.storeKey, mc.cdc))...)
Expand Down
24 changes: 24 additions & 0 deletions x/gov/client/rest/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec)

r.HandleFunc("/gov/proposals", queryProposalsWithParameterFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", RestProposalID), queryProposalHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc(
fmt.Sprintf("/gov/proposals/{%s}/proposer", RestProposalID),
queryProposerHandlerFn(cdc, cliCtx),
).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), queryDepositsHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositor), queryDepositHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/tally", RestProposalID), queryTallyOnProposalHandlerFn(cdc, cliCtx)).Methods("GET")
Expand Down Expand Up @@ -282,6 +286,26 @@ func queryDepositsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha
}
}

func queryProposerHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
strProposalID := vars[RestProposalID]

proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}

res, err := gcutils.QueryProposerByTxQuery(cdc, cliCtx, proposalID)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}

utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}

func queryDepositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
Expand Down
52 changes: 48 additions & 4 deletions x/gov/client/utils/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov/tags"
)

// Proposer contains metadata of a governance proposal used for querying a
// proposer.
type Proposer struct {
ProposalID uint64 `json:"proposal_id"`
Proposer string `json:"proposer"`
}

// 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.
Expand Down Expand Up @@ -133,8 +140,7 @@ func QueryVoteByTxQuery(
}
}

err = fmt.Errorf("address '%s' did not vote on proposalID %d", params.Voter, params.ProposalID)
return nil, err
return nil, fmt.Errorf("address '%s' did not vote on proposalID %d", params.Voter, params.ProposalID)
}

// QueryDepositByTxQuery will query for a single deposit via a direct txs tags
Expand Down Expand Up @@ -175,6 +181,44 @@ func QueryDepositByTxQuery(
}
}

err = fmt.Errorf("address '%s' did not deposit to proposalID %d", params.Depositor, params.ProposalID)
return nil, err
return nil, fmt.Errorf("address '%s' did not deposit to proposalID %d", params.Depositor, params.ProposalID)
}

// QueryProposerByTxQuery will query for a proposer of a governance proposal by
// ID.
func QueryProposerByTxQuery(
cdc *codec.Codec, cliCtx context.CLIContext, proposalID uint64,
) ([]byte, error) {

tags := []string{
fmt.Sprintf("%s='%s'", tags.Action, tags.ActionProposalSubmitted),
fmt.Sprintf("%s='%s'", tags.ProposalID, []byte(fmt.Sprintf("%d", proposalID))),
}

infos, err := tx.SearchTxs(cliCtx, cdc, tags)
if err != nil {
return nil, err
}

for _, info := range infos {
for _, msg := range info.Tx.GetMsgs() {
// there should only be a single proposal under the given conditions
if msg.Type() == gov.TypeMsgSubmitProposal {
subMsg := msg.(gov.MsgSubmitProposal)

proposer := Proposer{
ProposalID: proposalID,
Proposer: subMsg.Proposer.String(),
}

if cliCtx.Indent {
return cdc.MarshalJSONIndent(proposer, "", " ")
}

return cdc.MarshalJSON(proposer)
}
}
}

return nil, fmt.Errorf("failed to find the proposer for proposalID %d", proposalID)
}