Implement Proposal Proposer client interfaces (#3184)

This commit is contained in:
Alexander Bezobchuk 2018-12-21 12:30:46 -05:00 committed by Jack Zampolin
parent 2ce8722318
commit b0662aa4f6
9 changed files with 159 additions and 10 deletions

View File

@ -28,9 +28,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

View File

@ -566,10 +566,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) {

View File

@ -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
@ -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:

View File

@ -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"
@ -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"
@ -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)

View File

@ -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:

View File

@ -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
}

View File

@ -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))...)

View File

@ -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")
@ -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)

View File

@ -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.
@ -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
@ -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)
}