Implement Proposal Proposer client interfaces (#3184)
This commit is contained in:
parent
2ce8722318
commit
b0662aa4f6
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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))...)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue