Merge PR #2997: Split POST delegations endpoint

This commit is contained in:
Federico Kunze 2018-12-11 15:02:26 +01:00 committed by Christopher Goes
parent e1f0767ba8
commit 4ecbf0dd5f
11 changed files with 509 additions and 535 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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