From 4ecbf0dd5f3dd5e1b73bbe84f9463bd34a1540ba Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 11 Dec 2018 15:02:26 +0100 Subject: [PATCH] Merge PR #2997: Split POST delegations endpoint --- PENDING.md | 3 +- client/context/context.go | 16 +- client/lcd/lcd_test.go | 59 +-- client/lcd/swagger-ui/swagger.yaml | 605 ++++++++++++++++------------- client/utils/rest.go | 24 +- client/utils/utils.go | 4 +- x/bank/client/rest/sendtx.go | 5 +- x/gov/client/rest/rest.go | 15 +- x/ibc/client/rest/transfer.go | 5 +- x/slashing/client/rest/tx.go | 5 +- x/stake/client/rest/tx.go | 303 +++++---------- 11 files changed, 509 insertions(+), 535 deletions(-) diff --git a/PENDING.md b/PENDING.md index 3c56e92344..cc72812a0f 100644 --- a/PENDING.md +++ b/PENDING.md @@ -3,7 +3,8 @@ BREAKING CHANGES * Gaia REST API (`gaiacli advanced rest-server`) - * [\#3056](https://github.com/cosmos/cosmos-sdk/pull/3056) `generate_only` and `simulate` have moved from query arguments to POST requests body. + * [gaia-lite] [\#2191](https://github.com/cosmos/cosmos-sdk/issues/2191) Split `POST /stake/delegators/{delegatorAddr}/delegations` into `POST /stake/delegators/{delegatorAddr}/delegations`, `POST /stake/delegators/{delegatorAddr}/unbonding_delegations` and `POST /stake/delegators/{delegatorAddr}/redelegations` + * [gaia-lite] [\#3056](https://github.com/cosmos/cosmos-sdk/pull/3056) `generate_only` and `simulate` have moved from query arguments to POST requests body. * Gaia CLI (`gaiacli`) diff --git a/client/context/context.go b/client/context/context.go index df30374de9..9fac7c27a8 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -47,7 +47,7 @@ type CLIContext struct { JSON bool PrintResponse bool Verifier tmlite.Verifier - DryRun bool + Simulate bool GenerateOnly bool fromAddress types.AccAddress fromName string @@ -85,7 +85,7 @@ func NewCLIContext() CLIContext { JSON: viper.GetBool(client.FlagJson), PrintResponse: viper.GetBool(client.FlagPrintResponse), Verifier: verifier, - DryRun: viper.GetBool(client.FlagDryRun), + Simulate: viper.GetBool(client.FlagDryRun), GenerateOnly: viper.GetBool(client.FlagGenerateOnly), fromAddress: fromAddress, fromName: fromName, @@ -244,3 +244,15 @@ func (ctx CLIContext) WithVerifier(verifier tmlite.Verifier) CLIContext { ctx.Verifier = verifier return ctx } + +// WithGenerateOnly returns a copy of the context with updated GenerateOnly value +func (ctx CLIContext) WithGenerateOnly(generateOnly bool) CLIContext { + ctx.GenerateOnly = generateOnly + return ctx +} + +// WithSimulation returns a copy of the context with updated Simulate value +func (ctx CLIContext) WithSimulation(simulate bool) CLIContext { + ctx.Simulate = simulate + return ctx +} diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 34f8edbc90..bc64c23214 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -342,7 +342,7 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) { acc := getAccount(t, port, addr) // generate TX - res, body, _ := doSendWithGas(t, port, seed, name, password, addr, "simulate", 0, false, true) + res, body, _ := doSendWithGas(t, port, seed, name, "", addr, "simulate", 0, false, true) require.Equal(t, http.StatusOK, res.StatusCode, body) var msg auth.StdTx require.Nil(t, cdc.UnmarshalJSON([]byte(body), &msg)) @@ -1176,15 +1176,9 @@ func doDelegate(t *testing.T, port, seed, name, password string, chainID := viper.GetString(client.FlagChainID) jsonStr := []byte(fmt.Sprintf(`{ - "delegations": [ - { - "delegator_addr": "%s", - "validator_addr": "%s", - "delegation": { "denom": "%s", "amount": "%d" } - } - ], - "begin_unbondings": [], - "begin_redelegates": [], + "delegator_addr": "%s", + "validator_addr": "%s", + "delegation": { "denom": "%s", "amount": "%d" }, "base_req": { "name": "%s", "password": "%s", @@ -1197,11 +1191,10 @@ func doDelegate(t *testing.T, port, seed, name, password string, res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) - var results []ctypes.ResultBroadcastTxCommit - err := cdc.UnmarshalJSON([]byte(body), &results) + err := cdc.UnmarshalJSON([]byte(body), &resultTx) require.Nil(t, err) - return results[0] + return } func doBeginUnbonding(t *testing.T, port, seed, name, password string, @@ -1213,15 +1206,9 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, chainID := viper.GetString(client.FlagChainID) jsonStr := []byte(fmt.Sprintf(`{ - "delegations": [], - "begin_unbondings": [ - { - "delegator_addr": "%s", - "validator_addr": "%s", - "shares": "%d" - } - ], - "begin_redelegates": [], + "delegator_addr": "%s", + "validator_addr": "%s", + "shares": "%d", "base_req": { "name": "%s", "password": "%s", @@ -1231,14 +1218,13 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, } }`, delAddr, valAddr, amount, name, password, chainID, accnum, sequence)) - res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations", delAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) - var results []ctypes.ResultBroadcastTxCommit - err := cdc.UnmarshalJSON([]byte(body), &results) + err := cdc.UnmarshalJSON([]byte(body), &resultTx) require.Nil(t, err) - return results[0] + return } func doBeginRedelegation(t *testing.T, port, seed, name, password string, @@ -1251,16 +1237,10 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, chainID := viper.GetString(client.FlagChainID) jsonStr := []byte(fmt.Sprintf(`{ - "delegations": [], - "begin_unbondings": [], - "begin_redelegates": [ - { - "delegator_addr": "%s", - "validator_src_addr": "%s", - "validator_dst_addr": "%s", - "shares": "%d" - } - ], + "delegator_addr": "%s", + "validator_src_addr": "%s", + "validator_dst_addr": "%s", + "shares": "%d", "base_req": { "name": "%s", "password": "%s", @@ -1270,14 +1250,13 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, } }`, delAddr, valSrcAddr, valDstAddr, amount, name, password, chainID, accnum, sequence)) - res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/redelegations", delAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) - var results []ctypes.ResultBroadcastTxCommit - err := cdc.UnmarshalJSON([]byte(body), &results) + err := cdc.UnmarshalJSON([]byte(body), &resultTx) require.Nil(t, err) - return results[0] + return } func getValidators(t *testing.T, port string) []stake.Validator { diff --git a/client/lcd/swagger-ui/swagger.yaml b/client/lcd/swagger-ui/swagger.yaml index 0ecbe505fe..a76bdddd68 100644 --- a/client/lcd/swagger-ui/swagger.yaml +++ b/client/lcd/swagger-ui/swagger.yaml @@ -625,71 +625,6 @@ paths: description: Bech32 AccAddress of Delegator required: true type: string - post: - summary: Submit delegation - parameters: - - in: body - name: delegation - description: The password of the account to remove from the KMS - schema: - type: object - properties: - base_req: - "$ref": "#/definitions/BaseReq" - delegations: - type: array - items: - type: object - properties: - delegator_addr: - $ref: "#/definitions/Address" - validator_addr: - $ref: "#/definitions/ValidatorAddress" - delegation: - $ref: "#/definitions/Coin" - begin_unbondings: - type: array - items: - type: object - properties: - delegator_addr: - $ref: "#/definitions/Address" - validator_addr: - $ref: "#/definitions/ValidatorAddress" - shares: - type: string - example: "100" - begin_redelegates: - type: array - items: - type: object - properties: - delegator_addr: - $ref: "#/definitions/Address" - validator_src_addr: - $ref: "#/definitions/ValidatorAddress" - validator_dst_addr: - $ref: "#/definitions/ValidatorAddress" - shares: - type: string - example: "100" - tags: - - ICS21 - consumes: - - application/json - produces: - - application/json - responses: - 200: - description: OK - schema: - $ref: "#/definitions/BroadcastTxCommitResult" - 400: - description: Invalid delegator address or delegation body - 401: - description: Key password is wrong - 500: - description: Internal Server Error get: summary: Get all delegations from a delegator tags: @@ -702,12 +637,72 @@ paths: schema: type: array items: - type: object - "$ref": "#/definitions/Delegation" + $ref: "#/definitions/Delegation" 400: description: Invalid delegator address 500: description: Internal Server Error + post: + summary: Submit delegation + parameters: + - in: body + name: delegation + description: The password of the account to remove from the KMS + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + delegator_addr: + $ref: "#/definitions/Address" + validator_addr: + $ref: "#/definitions/ValidatorAddress" + delegation: + $ref: "#/definitions/Coin" + tags: + - ICS21 + consumes: + - application/json + produces: + - application/json + responses: + 200: + description: OK + schema: + $ref: "#/definitions/BroadcastTxCommitResult" + 400: + description: Invalid delegator address or delegation request body + 401: + description: Key password is wrong + 500: + description: Internal Server Error + /stake/delegators/{delegatorAddr}/delegations/{validatorAddr}: + parameters: + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string + get: + summary: Query the current delegation between a delegator and a validator + tags: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + $ref: "#/definitions/Delegation" + 400: + description: Invalid delegator address or validator address + 500: + description: Internal Server Error /stake/delegators/{delegatorAddr}/unbonding_delegations: parameters: - in: path @@ -727,12 +722,85 @@ paths: schema: type: array items: - type: object - "$ref": "#/definitions/UnbondingDelegation" + $ref: "#/definitions/UnbondingDelegation" 400: description: Invalid delegator address 500: description: Internal Server Error + post: + summary: Submit an unbonding delegation + parameters: + - in: query + name: simulate + description: if true, ignore the gas field and perform a simulation of a transaction, but don't broadcast it + required: false + type: boolean + - in: query + name: generate_only + description: if true, build an unsigned transaction and write it back + required: false + type: boolean + - in: body + name: delegation + description: The password of the account to remove from the KMS + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + delegator_addr: + $ref: "#/definitions/Address" + validator_addr: + $ref: "#/definitions/ValidatorAddress" + shares: + type: string + example: "100" + tags: + - ICS21 + consumes: + - application/json + produces: + - application/json + responses: + 200: + description: OK + schema: + $ref: "#/definitions/BroadcastTxCommitResult" + 400: + description: Invalid delegator address or unbonding delegation request body + 401: + description: Key password is wrong + 500: + description: Internal Server Error + /stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}: + parameters: + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string + get: + summary: Query all unbonding delegations between a delegator and a validator + tags: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: array + items: + $ref: "#/definitions/UnbondingDelegation" + 400: + description: Invalid delegator address or validator address + 500: + description: Internal Server Error /stake/delegators/{delegatorAddr}/redelegations: parameters: - in: path @@ -752,12 +820,58 @@ paths: schema: type: array items: - type: object - "$ref": "#/definitions/Redelegation" + $ref: "#/definitions/Redelegation" 400: description: Invalid delegator address 500: description: Internal Server Error + post: + summary: Submit a redelegation + parameters: + - in: query + name: simulate + description: if true, ignore the gas field and perform a simulation of a transaction, but don't broadcast it + required: false + type: boolean + - in: query + name: generate_only + description: if true, build an unsigned transaction and write it back + required: false + type: boolean + - in: body + name: delegation + description: The password of the account to remove from the KMS + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + delegator_addr: + $ref: "#/definitions/Address" + validator_src_addr: + $ref: "#/definitions/ValidatorAddress" + validator_dst_addr: + $ref: "#/definitions/ValidatorAddress" + shares: + type: string + example: "100" + tags: + - ICS21 + consumes: + - application/json + produces: + - application/json + responses: + 200: + description: OK + schema: + $ref: "#/definitions/BroadcastTxCommitResult" + 400: + description: Invalid delegator address or redelegation request body + 401: + description: Key password is wrong + 500: + description: Internal Server Error /stake/delegators/{delegatorAddr}/validators: parameters: - in: path @@ -835,63 +949,6 @@ paths: description: Invalid delegator address 500: description: Internal Server Error - /stake/delegators/{delegatorAddr}/delegations/{validatorAddr}: - parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string - - in: path - name: validatorAddr - description: Bech32 OperatorAddress of validator - required: true - type: string - get: - summary: Query the current delegation between a delegator and a validator - tags: - - ICS21 - produces: - - application/json - responses: - 200: - description: OK - schema: - $ref: "#/definitions/Delegation" - 400: - description: Invalid delegator address or validator address - 500: - description: Internal Server Error - /stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}: - parameters: - - in: path - name: delegatorAddr - description: Bech32 AccAddress of Delegator - required: true - type: string - - in: path - name: validatorAddr - description: Bech32 OperatorAddress of validator - required: true - type: string - get: - summary: Query all unbonding delegations between a delegator and a validator - tags: - - ICS21 - produces: - - application/json - responses: - 200: - description: OK - schema: - type: array - items: - type: object - "$ref": "#/definitions/UnbondingDelegation" - 400: - description: Invalid delegator address or validator address - 500: - description: Internal Server Error /stake/validators: get: summary: Get all validator candidates @@ -1116,7 +1173,7 @@ paths: type: object properties: base_req: - "$ref": "#/definitions/BaseReq" + $ref: "#/definitions/BaseReq" responses: 200: description: OK @@ -1147,7 +1204,7 @@ paths: type: object properties: base_req: - "$ref": "#/definitions/BaseReq" + $ref: "#/definitions/BaseReq" title: type: string description: @@ -1156,7 +1213,7 @@ paths: type: string example: "text" proposer: - "$ref": "#/definitions/Address" + $ref: "#/definitions/Address" initial_deposit: type: array items: @@ -1165,7 +1222,7 @@ paths: 200: description: OK schema: - "$ref": "#/definitions/BroadcastTxCommitResult" + $ref: "#/definitions/BroadcastTxCommitResult" 400: description: Invalid proposal body 401: @@ -1201,12 +1258,57 @@ paths: schema: type: array items: - "$ref": "#/definitions/TextProposal" + $ref: "#/definitions/TextProposal" 400: description: Invalid query parameters 500: description: Internal Server Error + /gov/proposals/{proposalId}: + get: + summary: Query a proposal + description: Query a proposal by id + produces: + - application/json + tags: + - ICS22 + parameters: + - type: string + name: proposalId + required: true + in: path + responses: + 200: + description: OK + schema: + $ref: "#/definitions/TextProposal" + 400: + description: Invalid proposal id + 500: + description: Internal Server Error /gov/proposals/{proposalId}/deposits: + get: + summary: Query deposits + description: Query deposits by proposalId + produces: + - application/json + tags: + - ICS22 + parameters: + - type: string + name: proposalId + required: true + in: path + responses: + 200: + description: OK + schema: + type: array + items: + $ref: "#/definitions/Deposit" + 400: + description: Invalid proposal id + 500: + description: Internal Server Error post: summary: Deposit tokens to a proposal description: Send transaction to deposit tokens to a proposal @@ -1230,9 +1332,9 @@ paths: type: object properties: base_req: - "$ref": "#/definitions/BaseReq" + $ref: "#/definitions/BaseReq" depositor: - "$ref": "#/definitions/Address" + $ref: "#/definitions/Address" amount: type: array items: @@ -1241,146 +1343,13 @@ paths: 200: description: OK schema: - "$ref": "#/definitions/BroadcastTxCommitResult" + $ref: "#/definitions/BroadcastTxCommitResult" 400: description: Invalid proposal id or deposit body 401: description: Key password is wrong 500: description: Internal Server Error - get: - summary: Query deposits - description: Query deposits by proposalId - produces: - - application/json - tags: - - ICS22 - parameters: - - type: string - name: proposalId - required: true - in: path - responses: - 200: - description: OK - schema: - type: array - items: - "$ref": "#/definitions/Deposit" - 400: - description: Invalid proposal id - 500: - description: Internal Server Error - /gov/proposals/{proposalId}/tally: - get: - summary: Get a proposal's tally result at the current time - description: Gets a proposal's tally result at the current time. If the proposal is pending deposits (i.e status 'DepositPeriod') it returns an empty tally result. - produces: - - application/json - tags: - - ICS22 - parameters: - - type: string - description: proposal id - name: proposalId - required: true - in: path - responses: - 200: - description: OK - schema: - $ref: "#/definitions/TallyResult" - 400: - description: Invalid proposal id - 500: - description: Internal Server Error - /gov/proposals/{proposalId}/votes: - post: - summary: Vote a proposal - description: Send transaction to vote a proposal - consumes: - - application/json - produces: - - application/json - tags: - - ICS22 - parameters: - - type: string - description: proposal id - name: proposalId - required: true - in: path - - description: valid value of `"option"` field can be `"yes"`, `"no"`, `"no_with_veto"` and `"abstain"` - name: post_vote_body - in: body - required: true - schema: - type: object - properties: - base_req: - "$ref": "#/definitions/BaseReq" - voter: - "$ref": "#/definitions/Address" - option: - type: string - example: "yes" - responses: - 200: - description: OK - schema: - "$ref": "#/definitions/BroadcastTxCommitResult" - 400: - description: Invalid proposal id or vote body - 401: - description: Key password is wrong - 500: - description: Internal Server Error - get: - summary: Query voters - description: Query voters information by proposalId - produces: - - application/json - tags: - - ICS22 - parameters: - - type: string - description: proposal id - name: proposalId - required: true - in: path - responses: - 200: - description: OK - schema: - type: array - items: - "$ref": "#/definitions/Vote" - 400: - description: Invalid proposal id - 500: - description: Internal Server Error - /gov/proposals/{proposalId}: - get: - summary: Query a proposal - description: Query a proposal by id - produces: - - application/json - tags: - - ICS22 - parameters: - - type: string - name: proposalId - required: true - in: path - responses: - 200: - description: OK - schema: - "$ref": "#/definitions/TextProposal" - 400: - description: Invalid proposal id - 500: - description: Internal Server Error /gov/proposals/{proposalId}/deposits/{depositor}: get: summary: Query deposit @@ -1411,6 +1380,71 @@ paths: description: Found no deposit 500: description: Internal Server Error + /gov/proposals/{proposalId}/votes: + get: + summary: Query voters + description: Query voters information by proposalId + produces: + - application/json + tags: + - ICS22 + parameters: + - type: string + description: proposal id + name: proposalId + required: true + in: path + responses: + 200: + description: OK + schema: + type: array + items: + $ref: "#/definitions/Vote" + 400: + description: Invalid proposal id + 500: + description: Internal Server Error + post: + summary: Vote a proposal + description: Send transaction to vote a proposal + consumes: + - application/json + produces: + - application/json + tags: + - ICS22 + parameters: + - type: string + description: proposal id + name: proposalId + required: true + in: path + - description: valid value of `"option"` field can be `"yes"`, `"no"`, `"no_with_veto"` and `"abstain"` + name: post_vote_body + in: body + required: true + schema: + type: object + properties: + base_req: + $ref: "#/definitions/BaseReq" + voter: + $ref: "#/definitions/Address" + option: + type: string + example: "yes" + responses: + 200: + description: OK + schema: + $ref: "#/definitions/BroadcastTxCommitResult" + 400: + description: Invalid proposal id or vote body + 401: + description: Key password is wrong + 500: + description: Internal Server Error /gov/proposals/{proposalId}/votes/{voter}: get: summary: Query vote @@ -1441,6 +1475,29 @@ paths: description: Found no vote 500: description: Internal Server Error + /gov/proposals/{proposalId}/tally: + get: + summary: Get a proposal's tally result at the current time + description: Gets a proposal's tally result at the current time. If the proposal is pending deposits (i.e status 'DepositPeriod') it returns an empty tally result. + produces: + - application/json + tags: + - ICS22 + parameters: + - type: string + description: proposal id + name: proposalId + required: true + in: path + responses: + 200: + description: OK + schema: + $ref: "#/definitions/TallyResult" + 400: + description: Invalid proposal id + 500: + description: Internal Server Error /gov/parameters/deposit: get: summary: Query governance deposit parameters @@ -1538,7 +1595,7 @@ definitions: tags: type: array items: - "$ref": "#/definitions/KVPair" + $ref: "#/definitions/KVPair" example: code: 0 data: data @@ -1567,7 +1624,7 @@ definitions: tags: type: array items: - "$ref": "#/definitions/KVPair" + $ref: "#/definitions/KVPair" example: code: 5 data: data @@ -1868,7 +1925,7 @@ definitions: total_deposit: type: array items: - "$ref": "#/definitions/Coin" + $ref: "#/definitions/Coin" voting_start_time: type: string Deposit: @@ -1877,11 +1934,11 @@ definitions: amount: type: array items: - "$ref": "#/definitions/Coin" + $ref: "#/definitions/Coin" proposal_id: type: integer depositor: - "$ref": "#/definitions/Address" + $ref: "#/definitions/Address" TallyResult: type: object properties: diff --git a/client/utils/rest.go b/client/utils/rest.go index 36ff05af8b..5917455ee3 100644 --- a/client/utils/rest.go +++ b/client/utils/rest.go @@ -159,21 +159,21 @@ func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req i // ValidateBasic performs basic validation of a BaseReq. If custom validation // logic is needed, the implementing request handler should perform those // checks manually. -func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool { - switch { - case len(br.Name) == 0: +func (br BaseReq) ValidateBasic(w http.ResponseWriter, cliCtx context.CLIContext) bool { + if !cliCtx.GenerateOnly && !cliCtx.Simulate { + switch { + case len(br.Password) == 0: + WriteErrorResponse(w, http.StatusUnauthorized, "password required but not specified") + return false + case len(br.ChainID) == 0: + WriteErrorResponse(w, http.StatusUnauthorized, "chain-id required but not specified") + return false + } + } + if len(br.Name) == 0 { WriteErrorResponse(w, http.StatusUnauthorized, "name required but not specified") return false - - case len(br.Password) == 0: - WriteErrorResponse(w, http.StatusUnauthorized, "password required but not specified") - return false - - case len(br.ChainID) == 0: - WriteErrorResponse(w, http.StatusUnauthorized, "chainID required but not specified") - return false } - return true } diff --git a/client/utils/utils.go b/client/utils/utils.go index 08a538eec6..6fde3ce6b5 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -34,14 +34,14 @@ func CompleteAndBroadcastTxCli(txBldr authtxb.TxBuilder, cliCtx context.CLIConte return err } - if txBldr.SimulateGas || cliCtx.DryRun { + if txBldr.SimulateGas || cliCtx.Simulate { txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, name, msgs) if err != nil { return err } fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.Gas) } - if cliCtx.DryRun { + if cliCtx.Simulate { return nil } diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index 7bb2640fdd..27cbc043c7 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -49,8 +49,11 @@ func SendRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIC return } + cliCtx = cliCtx.WithGenerateOnly(req.BaseReq.GenerateOnly) + cliCtx = cliCtx.WithSimulation(req.BaseReq.Simulate) + baseReq := req.BaseReq.Sanitize() - if !baseReq.ValidateBasic(w) { + if !baseReq.ValidateBasic(w, cliCtx) { return } diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 53deffbbe5..821da0cc7d 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -78,8 +78,11 @@ func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han return } + cliCtx = cliCtx.WithGenerateOnly(req.BaseReq.GenerateOnly) + cliCtx = cliCtx.WithSimulation(req.BaseReq.Simulate) + baseReq := req.BaseReq.Sanitize() - if !baseReq.ValidateBasic(w) { + if !baseReq.ValidateBasic(w, cliCtx) { return } @@ -123,8 +126,11 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF return } + cliCtx = cliCtx.WithGenerateOnly(req.BaseReq.GenerateOnly) + cliCtx = cliCtx.WithSimulation(req.BaseReq.Simulate) + baseReq := req.BaseReq.Sanitize() - if !baseReq.ValidateBasic(w) { + if !baseReq.ValidateBasic(w, cliCtx) { return } @@ -162,8 +168,11 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc return } + cliCtx = cliCtx.WithGenerateOnly(req.BaseReq.GenerateOnly) + cliCtx = cliCtx.WithSimulation(req.BaseReq.Simulate) + baseReq := req.BaseReq.Sanitize() - if !baseReq.ValidateBasic(w) { + if !baseReq.ValidateBasic(w, cliCtx) { return } diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index 19c9219711..704b663e62 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -43,8 +43,11 @@ func TransferRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context. return } + cliCtx = cliCtx.WithGenerateOnly(req.BaseReq.GenerateOnly) + cliCtx = cliCtx.WithSimulation(req.BaseReq.Simulate) + baseReq := req.BaseReq.Sanitize() - if !baseReq.ValidateBasic(w) { + if !baseReq.ValidateBasic(w, cliCtx) { return } diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index 5f33a1210c..ec28f48ed6 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -38,8 +38,11 @@ func unjailRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CL return } + cliCtx = cliCtx.WithGenerateOnly(req.BaseReq.GenerateOnly) + cliCtx = cliCtx.WithSimulation(req.BaseReq.Simulate) + baseReq := req.BaseReq.Sanitize() - if !baseReq.ValidateBasic(w) { + if !baseReq.ValidateBasic(w, cliCtx) { return } diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 5deb5b53c2..bb2bc0e7fa 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -2,81 +2,72 @@ package rest import ( "bytes" - "io/ioutil" "net/http" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" - authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" "github.com/cosmos/cosmos-sdk/x/stake" "github.com/gorilla/mux" - - ctypes "github.com/tendermint/tendermint/rpc/core/types" ) func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, kb keys.Keybase) { r.HandleFunc( "/stake/delegators/{delegatorAddr}/delegations", - delegationsRequestHandlerFn(cdc, kb, cliCtx), + postDelegationsHandlerFn(cdc, kb, cliCtx), + ).Methods("POST") + r.HandleFunc( + "/stake/delegators/{delegatorAddr}/unbonding_delegations", + postUnbondingDelegationsHandlerFn(cdc, kb, cliCtx), + ).Methods("POST") + r.HandleFunc( + "/stake/delegators/{delegatorAddr}/redelegations", + postRedelegationsHandlerFn(cdc, kb, cliCtx), ).Methods("POST") } type ( msgDelegationsInput struct { - DelegatorAddr string `json:"delegator_addr"` // in bech32 - ValidatorAddr string `json:"validator_addr"` // in bech32 - Delegation sdk.Coin `json:"delegation"` + BaseReq utils.BaseReq `json:"base_req"` + DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 + ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32 + Delegation sdk.Coin `json:"delegation"` } msgBeginRedelegateInput struct { - DelegatorAddr string `json:"delegator_addr"` // in bech32 - ValidatorSrcAddr string `json:"validator_src_addr"` // in bech32 - ValidatorDstAddr string `json:"validator_dst_addr"` // in bech32 - SharesAmount string `json:"shares"` + BaseReq utils.BaseReq `json:"base_req"` + DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 + ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` // in bech32 + ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` // in bech32 + SharesAmount sdk.Dec `json:"shares"` } msgBeginUnbondingInput struct { - DelegatorAddr string `json:"delegator_addr"` // in bech32 - ValidatorAddr string `json:"validator_addr"` // in bech32 - SharesAmount string `json:"shares"` - } - - // the request body for edit delegations - EditDelegationsReq struct { - BaseReq utils.BaseReq `json:"base_req"` - Delegations []msgDelegationsInput `json:"delegations"` - BeginUnbondings []msgBeginUnbondingInput `json:"begin_unbondings"` - BeginRedelegates []msgBeginRedelegateInput `json:"begin_redelegates"` + BaseReq utils.BaseReq `json:"base_req"` + DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 + ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32 + SharesAmount sdk.Dec `json:"shares"` } ) -// TODO: Split this up into several smaller functions, and remove the above nolint -// TODO: use sdk.ValAddress instead of sdk.AccAddress for validators in messages -// TODO: Seriously consider how to refactor...do we need to make it multiple txs? -// If not, we can just use CompleteAndBroadcastTxREST. -func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { +func postDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var req EditDelegationsReq + var req msgDelegationsInput - body, err := ioutil.ReadAll(r.Body) + err := utils.ReadRESTReq(w, r, cdc, &req) if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - err = cdc.UnmarshalJSON(body, &req) - if err != nil { - utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } + cliCtx = cliCtx.WithGenerateOnly(req.BaseReq.GenerateOnly) + cliCtx = cliCtx.WithSimulation(req.BaseReq.Simulate) baseReq := req.BaseReq.Sanitize() - if !baseReq.ValidateBasic(w) { + if !baseReq.ValidateBasic(w, cliCtx) { return } @@ -86,182 +77,98 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte return } - // build messages - messages := make([]sdk.Msg, len(req.Delegations)+ - len(req.BeginRedelegates)+ - len(req.BeginUnbondings)) - - i := 0 - for _, msg := range req.Delegations { - delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - if !bytes.Equal(info.GetPubKey().Address(), delAddr) { - utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") - return - } - - messages[i] = stake.MsgDelegate{ - DelegatorAddr: delAddr, - ValidatorAddr: valAddr, - Delegation: msg.Delegation, - } - - i++ + if !bytes.Equal(info.GetPubKey().Address(), req.DelegatorAddr) { + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") + return } - for _, msg := range req.BeginRedelegates { - delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - if !bytes.Equal(info.GetPubKey().Address(), delAddr) { - utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") - return - } - - valSrcAddr, err := sdk.ValAddressFromBech32(msg.ValidatorSrcAddr) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - valDstAddr, err := sdk.ValAddressFromBech32(msg.ValidatorDstAddr) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - shares, err := sdk.NewDecFromStr(msg.SharesAmount) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - messages[i] = stake.MsgBeginRedelegate{ - DelegatorAddr: delAddr, - ValidatorSrcAddr: valSrcAddr, - ValidatorDstAddr: valDstAddr, - SharesAmount: shares, - } - - i++ - } - - for _, msg := range req.BeginUnbondings { - delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - if !bytes.Equal(info.GetPubKey().Address(), delAddr) { - utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") - return - } - - valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - shares, err := sdk.NewDecFromStr(msg.SharesAmount) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - messages[i] = stake.MsgBeginUnbonding{ - DelegatorAddr: delAddr, - ValidatorAddr: valAddr, - SharesAmount: shares, - } - - i++ - } - - simulateGas, gas, err := client.ReadGasFlag(baseReq.Gas) + msg := stake.NewMsgDelegate(req.DelegatorAddr, req.ValidatorAddr, req.Delegation) + err = msg.ValidateBasic() if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment) - if !ok { + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, baseReq, []sdk.Msg{msg}, cdc) + } +} + +func postRedelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req msgBeginRedelegateInput + + err := utils.ReadRESTReq(w, r, cdc, &req) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } - txBldr := authtxb.TxBuilder{ - Codec: cdc, - Gas: gas, - GasAdjustment: adjustment, - SimulateGas: simulateGas, - ChainID: baseReq.ChainID, + cliCtx = cliCtx.WithGenerateOnly(req.BaseReq.GenerateOnly) + cliCtx = cliCtx.WithSimulation(req.BaseReq.Simulate) + + baseReq := req.BaseReq.Sanitize() + if !baseReq.ValidateBasic(w, cliCtx) { + return } - // sign messages - signedTxs := make([][]byte, len(messages[:])) - for i, msg := range messages { - // increment sequence for each message - txBldr = txBldr.WithAccountNumber(baseReq.AccountNumber) - txBldr = txBldr.WithSequence(baseReq.Sequence) - - baseReq.Sequence++ - - if baseReq.Simulate || txBldr.SimulateGas { - newBldr, err := utils.EnrichCtxWithGas(txBldr, cliCtx, baseReq.Name, []sdk.Msg{msg}) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - if baseReq.Simulate { - utils.WriteSimulationResponse(w, newBldr.Gas) - return - } - - txBldr = newBldr - } - - if baseReq.GenerateOnly { - utils.WriteGenerateStdTxResponse(w, txBldr, []sdk.Msg{msg}) - return - } - - txBytes, err := txBldr.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg}) - if err != nil { - utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) - return - } - - signedTxs[i] = txBytes + info, err := kb.Get(baseReq.Name) + if err != nil { + utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) + return } - // send - // XXX the operation might not be atomic if a tx fails - // should we have a sdk.MultiMsg type to make sending atomic? - results := make([]*ctypes.ResultBroadcastTxCommit, len(signedTxs[:])) - for i, txBytes := range signedTxs { - res, err := cliCtx.BroadcastTx(txBytes) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - results[i] = res + if !bytes.Equal(info.GetPubKey().Address(), req.DelegatorAddr) { + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") + return } - utils.PostProcessResponse(w, cdc, results, cliCtx.Indent) + msg := stake.NewMsgBeginRedelegate(req.DelegatorAddr, req.ValidatorSrcAddr, req.ValidatorDstAddr, req.SharesAmount) + err = msg.ValidateBasic() + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, baseReq, []sdk.Msg{msg}, cdc) + } +} + +func postUnbondingDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req msgBeginUnbondingInput + + err := utils.ReadRESTReq(w, r, cdc, &req) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + cliCtx = cliCtx.WithGenerateOnly(req.BaseReq.GenerateOnly) + cliCtx = cliCtx.WithSimulation(req.BaseReq.Simulate) + + baseReq := req.BaseReq.Sanitize() + if !baseReq.ValidateBasic(w, cliCtx) { + return + } + + info, err := kb.Get(baseReq.Name) + if err != nil { + utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) + return + } + + if !bytes.Equal(info.GetPubKey().Address(), req.DelegatorAddr) { + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") + return + } + + msg := stake.NewMsgBeginUnbonding(req.DelegatorAddr, req.ValidatorAddr, req.SharesAmount) + err = msg.ValidateBasic() + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + utils.CompleteAndBroadcastTxREST(w, r, cliCtx, baseReq, []sdk.Msg{msg}, cdc) } }