diff --git a/PENDING.md b/PENDING.md index 79c8d1aa1a3e..7ad396b7b449 100644 --- a/PENDING.md +++ b/PENDING.md @@ -128,7 +128,7 @@ FEATURES * [gaia-lite] [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add support for `generate_only=true` query argument to generate offline unsigned transactions * [gaia-lite] [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) Add /sign endpoint to sign transactions generated with `generate_only=true`. * [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint. - * [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}` + * [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}`, replace `proposal-id` with `proposalId` in all gov endpoints * [gaia-lite] [\#2478](https://github.com/cosmos/cosmos-sdk/issues/2478) Add query gov proposal's deposits endpoint * [gaia-lite] [\#2477](https://github.com/cosmos/cosmos-sdk/issues/2477) Add query validator's outgoing redelegations and unbonding delegations endpoints diff --git a/client/keys/delete.go b/client/keys/delete.go index 84adc00204ca..406843663d38 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" keys "github.com/cosmos/cosmos-sdk/crypto/keys" + keyerror "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" "github.com/gorilla/mux" "github.com/spf13/cobra" @@ -80,9 +81,16 @@ func DeleteKeyRequestHandler(w http.ResponseWriter, r *http.Request) { return } - // TODO handle error if key is not available or pass is wrong err = kb.Delete(name, m.Password) - if err != nil { + if keyerror.IsErrKeyNotFound(err) { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte(err.Error())) + return + } else if keyerror.IsErrWrongPassword(err) { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(err.Error())) + return + } else if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return diff --git a/client/keys/show.go b/client/keys/show.go index b567daf12435..71123e7da77d 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/cli" + "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" ) const ( @@ -108,12 +109,14 @@ func GetKeyRequestHandler(indent bool) http.HandlerFunc { } info, err := GetKeyInfo(name) - // TODO: check for the error if key actually does not exist, instead of - // assuming this as the reason - if err != nil { + if keyerror.IsErrKeyNotFound(err) { w.WriteHeader(http.StatusNotFound) w.Write([]byte(err.Error())) return + } else if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return } keyOutput, err := bechKeyOut(info) diff --git a/client/keys/update.go b/client/keys/update.go index abf616a65353..5f4c92e6f624 100644 --- a/client/keys/update.go +++ b/client/keys/update.go @@ -10,6 +10,7 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" + "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" ) func updateKeyCommand() *cobra.Command { @@ -83,12 +84,19 @@ func UpdateKeyRequestHandler(w http.ResponseWriter, r *http.Request) { getNewpass := func() (string, error) { return m.NewPassword, nil } - // TODO check if account exists and if password is correct err = kb.Update(name, m.OldPassword, getNewpass) - if err != nil { + if keyerror.IsErrKeyNotFound(err) { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte(err.Error())) + return + } else if keyerror.IsErrWrongPassword(err) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(err.Error())) return + } else if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return } w.Header().Set("Content-Type", "application/json") diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index b7a34fb7b716..cb25721e891d 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -959,7 +959,7 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Acc } func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing.ValidatorSigningInfo { - res, body := Request(t, port, "GET", fmt.Sprintf("/slashing/signing_info/%s", validatorPubKey), nil) + res, body := Request(t, port, "GET", fmt.Sprintf("/slashing/validators/%s/signing_info", validatorPubKey), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var signingInfo slashing.ValidatorSigningInfo diff --git a/client/lcd/swagger-ui/swagger.yaml b/client/lcd/swagger-ui/swagger.yaml index cde32050d978..86b6ec6813fa 100644 --- a/client/lcd/swagger-ui/swagger.yaml +++ b/client/lcd/swagger-ui/swagger.yaml @@ -2,15 +2,23 @@ swagger: '2.0' info: version: 1.1.0 - title: Gaia-Lite (former LCD) to interface with Cosmos BaseServer via REST - description: Specification for Gaia-lite provided by `gaiacli rest-server` + title: Gaia-Lite for Cosmos + description: A REST interface for state queries, transaction generation, signing, and broadcast. tags: - name: ICS0 description: Tendermint APIs, such as query blocks, transactions and validatorset +- name: ICS1 + description: Key management APIs - name: ICS20 - description: Create and sign a send tx + description: Create, sign and broadcast transactions +- name: ICS21 + description: Stake module APIs +- name: ICS22 + description: Governance module APIs +- name: ICS23 + description: Slashing module APIs - name: version - description: Information about the app version + description: Query app version schemes: - https securityDefinitions: @@ -25,16 +33,18 @@ paths: description: Get the version of gaia-lite running locally to compare against expected responses: 200: - description: Plaintext version i.e. "v0.5.0" + description: Plaintext version i.e. "v0.25.0" /node_version: get: summary: Version of the connected node tags: - - ICS0 + - version description: Get the version of the SDK running on the connected node to compare against expected responses: 200: - description: Plaintext version i.e. "v0.5.0" + description: Plaintext version i.e. "v0.25.0" + 500: + description: failed to query node version /node_info: get: description: Information about the connected node @@ -71,6 +81,8 @@ paths: type: array items: type: string + 500: + description: Failed to query node status /syncing: get: summary: Syncing state of node @@ -80,6 +92,8 @@ paths: responses: 200: description: '"true" or "false"' + 500: + description: Server internal error /blocks/latest: get: summary: Get the latest block @@ -91,7 +105,9 @@ paths: 200: description: The latest block schema: - $ref: "#/definitions/QueryBlock" + $ref: "#/definitions/BlockQuery" + 500: + description: Server internal error /blocks/{height}: get: summary: Get a block at a certain height @@ -109,9 +125,13 @@ paths: 200: description: The block at a specific height schema: - $ref: "#/definitions/QueryBlock" + $ref: "#/definitions/BlockQuery" 404: - description: Block at height is not available + description: Request block height doesn't + 400: + description: Invalid height + 500: + description: Server internal error /validatorsets/latest: get: summary: Get the latest validator set @@ -130,7 +150,9 @@ paths: validators: type: array items: - $ref: "#/definitions/Validator" + $ref: "#/definitions/TendermintValidator" + 500: + description: Server internal error /validatorsets/{height}: get: summary: Get a validator set a certain height @@ -155,9 +177,13 @@ paths: validators: type: array items: - $ref: "#/definitions/Validator" + $ref: "#/definitions/TendermintValidator" 404: description: Block at height not available + 400: + description: Invalid height + 500: + description: Server internal error /txs/{hash}: get: summary: Get a Tx by hash @@ -176,8 +202,8 @@ paths: description: Tx with the provided hash schema: $ref: "#/definitions/TxQuery" - 404: - description: Tx not available for provided hash + 500: + description: Internal Server Error /txs: get: tags: @@ -207,8 +233,10 @@ paths: type: array items: $ref: "#/definitions/TxQuery" - 404: - description: Pagination is out of bounds + 400: + description: Invalid search tags + 500: + description: Internal Server Error post: tags: - ICS0 @@ -224,12 +252,20 @@ paths: description: Build a StdTx transaction and serilize it to a byte array with amino, then the `"tx"` field in the post body will be the base64 encoding of the byte array. The supported return types includes `"block"`(return after tx commit), `"sync"`(return afer CheckTx) and `"async"`(return right away). required: true schema: - $ref: "#/definitions/TendertmintTx" + type: object + properties: + tx: + type: string + return: + type: string + example: block responses: 200: description: Broadcast tx result schema: $ref: "#/definitions/BroadcastTxCommitResult" + 500: + description: Internal Server Error /tx/sign: post: tags: @@ -246,14 +282,36 @@ paths: description: sign tx required: true schema: - $ref: "#/definitions/TxSign" + type: object + properties: + tx: + $ref: "#/definitions/StdTx" + name: + type: string + password: + type: string + chain_id: + type: string + account_number: + type: string + example: "0" + sequence: + type: string + example: "0" + append_sig: + type: boolean + example: true responses: 200: description: The signed Tx schema: $ref: "#/definitions/StdTx" + 400: + description: The Tx was malformated or key doesn't exist 401: - description: Account name and/or password where wrong + description: Key password is wrong + 500: + description: Server internal error /tx/broadcast: post: tags: @@ -270,7 +328,10 @@ paths: description: broadcast tx required: true schema: - $ref: "#/definitions/TxBroadcast" + type: object + properties: + tx: + $ref: "#/definitions/StdTx" responses: 202: description: Tx was send and will probably be added to the next block @@ -278,6 +339,8 @@ paths: $ref: "#/definitions/BroadcastTxCommitResult" 400: description: The Tx was malformated + 500: + description: Server internal error /bank/balances/{address}: get: summary: Get the account balances @@ -299,7 +362,9 @@ paths: items: $ref: "#/definitions/Coin" 204: - description: There is no data for the requested account. This is not a 404 as the account might exist, just does not hold data. + description: There is no data for the requested account + 500: + description: Server internal error /bank/accounts/{address}/transfers: post: summary: Send coins (build -> sign -> send) @@ -345,7 +410,11 @@ paths: schema: $ref: "#/definitions/BroadcastTxCommitResult" 400: - description: The Tx was malformated + description: Invalid request + 401: + description: Key password is wrong + 500: + description: Server internal error /keys: get: summary: List of accounts stored locally @@ -359,7 +428,9 @@ paths: schema: type: array items: - $ref: '#/definitions/Account' + $ref: '#/definitions/KeyOutput' + 500: + description: Server internal error post: summary: Create a new account locally tags: @@ -389,7 +460,13 @@ paths: 200: description: Returns account information of the created key schema: - $ref: "#/definitions/Account" + $ref: "#/definitions/KeyOutput" + 400: + description: Invalid request + 409: + description: Key name confliction + 500: + description: Server internal error /keys/seed: get: summary: Create a new seed to create a new account with @@ -397,10 +474,10 @@ paths: - ICS1 responses: 200: - description: 16 word Seed + description: 24 word Seed schema: type: string - example: blossom pool issue kidney elevator blame furnace winter account merry vessel security depend exact travel bargain problem jelly rural net again mask roast chest + example: blossom pool issue kidney elevator blame furnace winter account merry vessel security depend exact travel bargain problem jelly rural net again mask roast chest /keys/{name}/recover: post: summary: Recover a account from a seed @@ -433,7 +510,13 @@ paths: 200: description: Returns account information of the recovered key schema: - $ref: "#/definitions/Account" + $ref: "#/definitions/KeyOutput" + 400: + description: Invalid request + 409: + description: Key name confliction + 500: + description: Server internal error /keys/{name}: parameters: - in: path @@ -451,9 +534,9 @@ paths: 200: description: Locally stored account schema: - $ref: "#/definitions/Account" + $ref: "#/definitions/KeyOutput" 404: - description: Account is not available + description: Key doesn't exist put: summary: Update the password for this account in the KMS tags: @@ -478,9 +561,9 @@ paths: 200: description: Updated password 401: - description: Password is wrong + description: Key password is wrong 404: - description: Account is not available + description: Key doesn't exist delete: summary: Remove an account tags: @@ -502,9 +585,9 @@ paths: 200: description: Removed account 401: - description: Password is wrong + description: Key password is wrong 404: - description: Account is not available + description: Key doesn't exist /auth/accounts/{address}: get: summary: Get the account information on blockchain @@ -522,190 +605,979 @@ paths: 200: description: Account information on the blockchain schema: - $ref: "#/definitions/AccountQueryResponse" - 404: - description: Account is not available - -definitions: - CheckTxResult: - type: object - properties: - code: - type: integer - data: - type: string - gas_used: - type: integer - gas_wanted: - type: integer - info: - type: string - log: - type: string + type: object + properties: + type: + type: string + value: + type: object + properties: + account_number: + type: string + address: + type: string + coins: + type: array + items: + $ref: "#/definitions/Coin" + public_key: + type: string + sequence: + type: string + 204: + description: No content about this account address + 500: + description: Server internel error + /stake/delegators/{delegatorAddr}/delegations: + parameters: + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + post: + summary: Submit 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" + 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: - type: array - items: - "$ref": "#/definitions/KVPair" - example: - code: 0 - data: data - log: log - gas_used: 5000 - gas_wanted: 10000 - info: info + - 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: - - '' - - '' - DeliverTxResult: - type: object - properties: - code: - type: integer - data: - type: string - gas_used: - type: integer - gas_wanted: - type: integer - info: - type: string - log: - type: string + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: array + items: + type: object + "$ref": "#/definitions/Delegation" + 400: + description: Invalid delegator address + 500: + description: Internal Server Error + /stake/delegators/{delegatorAddr}/unbonding_delegations: + parameters: + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + get: + summary: Get all unbonding delegations from a delegator tags: - type: array - items: - "$ref": "#/definitions/KVPair" - example: - code: 5 - data: data - log: log - gas_used: 5000 - gas_wanted: 10000 - info: info + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: array + items: + type: object + "$ref": "#/definitions/UnbondingDelegation" + 400: + description: Invalid delegator address + 500: + description: Internal Server Error + /stake/delegators/{delegatorAddr}/redelegations: + parameters: + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + get: + summary: Get all redelegations from a delegator tags: - - '' - - '' - BroadcastTxCommitResult: - type: object - properties: - check_tx: - $ref: "#/definitions/CheckTxResult" - deliver_tx: - $ref: "#/definitions/DeliverTxResult" - hash: - $ref: "#/definitions/Hash" - height: - type: integer - KVPair: - type: object - properties: - key: - type: string - value: - type: string - Fee: - type: object - properties: - gas: - type: string - amount: - type: array - items: - $ref: "#/definitions/Coin" - Msg: - type: string - Address: - type: string - description: bech32 encoded addres - example: cosmoszgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq - ValidatorAddress: - type: string - description: bech32 encoded addres - example: cosmosvaloper:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq - PubKey: - type: object - properties: - type: - type: string - example: "tendermint/PubKeySecp256k1" - value: - type: string - example: "Avz04VhtKJh8ACCVzlI8aTosGy0ikFXKIVHQ3jKMrosH" - ValidatorPubKey: - type: string - description: bech32 encoded public key - example: cosmosvalconspub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq - Coin: - type: object - properties: - denom: - type: string - example: steak - amount: - type: string - example: "50" - Hash: - type: string - example: EE5F3404034C524501629B56E0DDC38FAD651F04 - Result: - type: object - properties: - log: - type: string - gas_wanted: - type: string - example: "0" - gas_used: - type: string - example: "0" + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: array + items: + type: object + "$ref": "#/definitions/Redelegation" + 400: + description: Invalid delegator address + 500: + description: Internal Server Error + /stake/delegators/{delegatorAddr}/validators: + parameters: + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + get: + summary: Query all validators that a delegator is bonded to tags: - type: array - items: - $ref: "#/definitions/KVPair" - TxQuery: - type: object - properties: - hash: - type: string - height: - type: number - tx: - $ref: "#/definitions/StdTx" - result: - $ref: "#/definitions/Result" - TendertmintTx: - type: object - properties: - tx: - type: string - return: - type: string - example: block - TxBroadcast: - type: object - properties: - tx: - $ref: "#/definitions/StdTx" - TxSign: - type: object - properties: - tx: - $ref: "#/definitions/StdTx" - name: - type: string - password: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: array + items: + $ref: "#/definitions/Validator" + 400: + description: Invalid delegator address + 500: + description: Internal Server Error + /stake/delegators/{delegatorAddr}/validators/{validatorAddr}: + parameters: + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + - in: path + name: validatorAddr + description: Bech32 ValAddress of Delegator + required: true + type: string + get: + summary: Query a validator that a delegator is bonded to + tags: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + $ref: "#/definitions/Validator" + 400: + description: Invalid delegator address or validator address + 500: + description: Internal Server Error + /stake/delegators/{delegatorAddr}/txs: + parameters: + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + get: + summary: Get all staking txs (i.e msgs) from a delegator + tags: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: array + items: + $ref: "#/definitions/TxQuery" + 204: + description: No staking transaction about this delegator address + 400: + 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 + tags: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: array + items: + $ref: "#/definitions/Validator" + 500: + description: Internal Server Error + /stake/validators/{validatorAddr}: + parameters: + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string + get: + summary: Query the information from a single validator + tags: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + $ref: "#/definitions/Validator" + 400: + description: Invalid validator address + 500: + description: Internal Server Error + /stake/validators/{validatorAddr}/unbonding_delegations: + parameters: + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string + get: + summary: Get all unbonding delegations from a validator + tags: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: array + items: + $ref: "#/definitions/UnbondingDelegation" + 400: + description: Invalid validator address + 500: + description: Internal Server Error + /stake/validators/{validatorAddr}/redelegations: + parameters: + - in: path + name: validatorAddr + description: Bech32 OperatorAddress of validator + required: true + type: string + get: + summary: Get all outgoing redelegations from a validator + tags: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: array + items: + $ref: "#/definitions/Redelegation" + 400: + description: Invalid validator address + 500: + description: Internal Server Error + /stake/pool: + get: + summary: Get the current state of the staking pool + tags: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: object + properties: + loose_tokens: + type: string + bonded_tokens: + type: string + inflation_last_time: + type: string + inflation: + type: string + date_last_commission_reset: + type: string + prev_bonded_shares: + type: string + 500: + description: Internal Server Error + /stake/parameters: + get: + summary: Get the current staking parameter values + tags: + - ICS21 + produces: + - application/json + responses: + 200: + description: OK + schema: + type: object + properties: + inflation_rate_change: + type: string + inflation_max: + type: string + inflation_min: + type: string + goal_bonded: + type: string + unbonding_time: + type: string + max_validators: + type: integer + bond_denom: + type: string + 500: + description: Internal Server Error + /slashing/validators/{validatorPubKey}/signing_info: + get: + summary: Get sign info of given validator + description: Get sign info of given validator + produces: + - application/json + tags: + - ICS23 + parameters: + - type: string + description: Bech32 validator public key + name: validatorPubKey + required: true + in: path + responses: + 200: + description: OK + schema: + type: object + properties: + start_height: + type: string + index_offset: + type: string + jailed_until: + type: string + missed_blocks_counter: + type: string + 204: + description: No sign info of this validator + 400: + description: Invalid validator public key + 500: + description: Internal Server Error + /slashing/validators/{validatorAddr}/unjail: + post: + summary: Unjail a jailed validator + description: Send transaction to unjail a jailed validator + consumes: + - application/json + produces: + - application/json + tags: + - ICS23 + 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 + - type: string + description: Bech32 validator address + name: validatorAddr + required: true + in: path + - description: '' + name: UnjailBody + in: body + required: true + schema: + type: object + properties: + base_req: + "$ref": "#/definitions/BaseReq" + responses: + 200: + description: OK + schema: + $ref: "#/definitions/BroadcastTxCommitResult" + 400: + description: Invalid validator address or base_req + 401: + description: Key password is wrong + 500: + description: Internal Server Error + /gov/proposals: + post: + summary: Submit a proposal + description: Send transaction to submit a proposal + consumes: + - application/json + produces: + - application/json + tags: + - ICS22 + 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 + - description: valid value of `"proposal_type"` can be `"text"`, `"parameter_change"`, `"software_upgrade"` + name: post_proposal_body + in: body + required: true + schema: + type: object + properties: + base_req: + "$ref": "#/definitions/BaseReq" + title: + type: string + description: + type: string + proposal_type: + type: string + example: "text" + proposer: + "$ref": "#/definitions/Address" + initial_deposit: + type: array + items: + $ref: "#/definitions/Coin" + responses: + 200: + description: OK + schema: + "$ref": "#/definitions/BroadcastTxCommitResult" + 400: + description: Invalid proposal body + 401: + description: Key password is wrong + 500: + description: Internal Server Error + get: + summary: Query proposals + description: Query proposals information with parameters + produces: + - application/json + tags: + - ICS22 + parameters: + - in: query + name: voter + description: voter address + required: false + type: string + - in: query + name: depositer + description: depositer address + required: false + type: string + - in: query + name: status + description: proposal status, valid values can be `"deposit_period"`, `"voting_period"`, `"passed"`, `"rejected"` + required: false + type: string + responses: + 200: + description: OK + schema: + type: array + items: + "$ref": "#/definitions/TextProposal" + 400: + description: Invalid query parameters + 500: + description: Internal Server Error + /gov/proposals/{proposalId}/deposits: + post: + summary: Deposit tokens to a proposal + description: Send transaction to deposit tokens to a proposal + consumes: + - application/json + produces: + - application/json + tags: + - ICS22 + 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 + - type: string + description: proposal id + name: proposalId + required: true + in: path + - description: '' + name: post_deposit_body + in: body + required: true + schema: + type: object + properties: + base_req: + "$ref": "#/definitions/BaseReq" + depositer: + "$ref": "#/definitions/Address" + amount: + type: array + items: + $ref: "#/definitions/Coin" + responses: + 200: + description: OK + schema: + "$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}/votes: + post: + summary: Vote a proposal + description: Send transaction to vote a proposal + consumes: + - application/json + produces: + - application/json + tags: + - ICS22 + 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 + - 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/{depositer}: + get: + summary: Query deposit + description: Query deposit by proposalId and depositer address + produces: + - application/json + tags: + - ICS22 + parameters: + - type: string + description: proposal id + name: proposalId + required: true + in: path + - type: string + description: Bech32 depositer address + name: depositer + required: true + in: path + responses: + 200: + description: OK + schema: + $ref: "#/definitions/Deposit" + 400: + description: Invalid proposal id or depositer address + 404: + description: Found no deposit + 500: + description: Internal Server Error + /gov/proposals/{proposalId}/votes/{voter}: + get: + summary: Query vote + description: Query vote information by proposalId and voter address + produces: + - application/json + tags: + - ICS22 + parameters: + - type: string + description: proposal id + name: proposalId + required: true + in: path + - type: string + description: Bech32 voter address + name: voter + required: true + in: path + responses: + 200: + description: OK + schema: + $ref: "#/definitions/Vote" + 400: + description: Invalid proposal id or voter address + 404: + description: Found no vote + 500: + description: Internal Server Error + +definitions: + CheckTxResult: + type: object + properties: + code: + type: integer + data: type: string - chain_id: + gas_used: + type: integer + gas_wanted: + type: integer + info: type: string - account_number: + log: type: string - example: "0" - sequence: + tags: + type: array + items: + "$ref": "#/definitions/KVPair" + example: + code: 0 + data: data + log: log + gas_used: 5000 + gas_wanted: 10000 + info: info + tags: + - '' + - '' + DeliverTxResult: + type: object + properties: + code: + type: integer + data: type: string - example: "0" - append_sig: - type: boolean - example: true + gas_used: + type: integer + gas_wanted: + type: integer + info: + type: string + log: + type: string + tags: + type: array + items: + "$ref": "#/definitions/KVPair" + example: + code: 5 + data: data + log: log + gas_used: 5000 + gas_wanted: 10000 + info: info + tags: + - '' + - '' + BroadcastTxCommitResult: + type: object + properties: + check_tx: + $ref: "#/definitions/CheckTxResult" + deliver_tx: + $ref: "#/definitions/DeliverTxResult" + hash: + $ref: "#/definitions/Hash" + height: + type: integer + KVPair: + type: object + properties: + key: + type: string + value: + type: string + Msg: + type: string + Address: + type: string + description: bech32 encoded address + example: cosmos1depk54cuajgkzea6zpgkq36tnjwdzv4afc3d27 + ValidatorAddress: + type: string + description: bech32 encoded address + example: cosmosvaloper1depk54cuajgkzea6zpgkq36tnjwdzv4avv9cxd + Coin: + type: object + properties: + denom: + type: string + example: steak + amount: + type: string + example: "50" + Hash: + type: string + example: EE5F3404034C524501629B56E0DDC38FAD651F04 + TxQuery: + type: object + properties: + hash: + type: string + height: + type: number + tx: + $ref: "#/definitions/StdTx" + result: + type: object + properties: + log: + type: string + gas_wanted: + type: string + example: "0" + gas_used: + type: string + example: "0" + tags: + type: array + items: + $ref: "#/definitions/KVPair" StdTx: type: object properties: @@ -714,7 +1586,14 @@ definitions: items: $ref: "#/definitions/Msg" fee: - $ref: "#/definitions/Fee" + type: object + properties: + gas: + type: string + amount: + type: array + items: + $ref: "#/definitions/Coin" memo: type: string signature: @@ -724,51 +1603,37 @@ definitions: type: string example: MEUCIQD02fsDPra8MtbRsyB1w7bqTM55Wu138zQbFcWx4+CFyAIge5WNPfKIuvzBZ69MyqHsqD8S1IwiEp+iUb6VSdtlpgY= pub_key: - $ref: "#/definitions/PubKey" + type: object + properties: + type: + type: string + example: "tendermint/PubKeySecp256k1" + value: + type: string + example: "Avz04VhtKJh8ACCVzlI8aTosGy0ikFXKIVHQ3jKMrosH" account_number: type: string example: "0" sequence: type: string example: "0" - Account: + KeyOutput: type: object properties: name: type: string example: Main Account address: - $ref: "#/definitions/Address" + type: string + example: cosmos1depk54cuajgkzea6zpgkq36tnjwdzv4afc3d27 pub_key: type: string - example: "cosmospub1addwnpepqfgv3pakxazq2fgs8tmmhmzsrs94fptl7kyztyxprjpf0mkus3h7cxqe70s" + example: "cosmospub1addwnpepqtqc88gfdxyzcdm2eqr3tnlnxnelyqehy8k95qzgwdz5zccdft9rq5q7wj2" type: type: string example: local seed: type: string - AccountInfo: - type: object - properties: - account_number: - type: string - address: - type: string - coins: - type: array - items: - $ref: "#/definitions/Coin" - public_key: - type: string - sequence: - type: string - AccountQueryResponse: - type: object - properties: - type: - type: string - value: - $ref: "#/definitions/AccountInfo" BlockID: type: object properties: @@ -808,6 +1673,8 @@ definitions: $ref: "#/definitions/Hash" validators_hash: $ref: "#/definitions/Hash" + next_validators_hash: + $ref: "#/definitions/Hash" consensus_hash: $ref: "#/definitions/Hash" app_hash: @@ -816,6 +1683,8 @@ definitions: $ref: "#/definitions/Hash" evidence_hash: $ref: "#/definitions/Hash" + proposer_address: + $ref: "#/definitions/Address" Block: type: object properties: @@ -861,18 +1730,16 @@ definitions: signature: type: string example: '7uTC74QlknqYWEwg7Vn6M8Om7FuZ0EO4bjvuj6rwH1mTUJrRuMMZvAAqT9VjNgP0RA/TDp6u/92AqrZfXJSpBQ==' - BlockMeta: - type: object - properties: - header: - $ref: "#/definitions/BlockHeader" - block_id: - $ref: "#/definitions/BlockID" - QueryBlock: + BlockQuery: type: object properties: block_meta: - $ref: "#/definitions/BlockMeta" + type: object + properties: + header: + $ref: "#/definitions/BlockHeader" + block_id: + $ref: "#/definitions/BlockID" block: $ref: "#/definitions/Block" BaseReq: @@ -882,6 +1749,7 @@ definitions: type: string password: type: string + example: "12345678" chain_id: type: string account_number: @@ -896,16 +1764,170 @@ definitions: gas_adjustment: type: string example: "1.2" - Validator: + TendermintValidator: type: object properties: address: $ref: '#/definitions/ValidatorAddress' pub_key: - $ref: "#/definitions/ValidatorPubKey" + type: string + example: cosmosvalconspub1zcjduepq7sjfglw7ra4mjxpw4ph7dtdhdheh7nz8dfgl6t8u2n5szuuql9mqsrwquu power: - type: number - example: 1000 + type: string + example: "1000" accum: - type: number - example: 1000 + type: string + example: "1000" + TextProposal: + type: object + properties: + proposal_id: + type: integer + title: + type: string + description: + type: string + proposal_type: + type: string + proposal_status: + type: string + tally_result: + type: object + properties: + yes: + type: string + abstain: + type: string + no: + type: string + no_with_veto: + type: string + submit_time: + type: string + total_deposit: + type: array + items: + "$ref": "#/definitions/Coin" + voting_start_time: + type: string + Deposit: + type: object + properties: + amount: + type: array + items: + "$ref": "#/definitions/Coin" + proposal_id: + type: integer + depositer: + "$ref": "#/definitions/Address" + Vote: + type: object + properties: + voter: + type: string + proposal_id: + type: integer + option: + type: string + Validator: + type: object + properties: + operator_address: + $ref: '#/definitions/ValidatorAddress' + consensus_pubkey: + type: string + example: cosmosvalconspub1zcjduepq7sjfglw7ra4mjxpw4ph7dtdhdheh7nz8dfgl6t8u2n5szuuql9mqsrwquu + jailed: + type: boolean + status: + type: integer + tokens: + type: string + delegator_shares: + type: string + description: + type: object + properties: + moniker: + type: string + identity: + type: string + website: + type: string + details: + type: string + bond_height: + type: string + example: '0' + bond_intra_tx_counter: + type: integer + example: 0 + unbonding_height: + type: string + example: '0' + unbonding_time: + type: string + example: '1970-01-01T00:00:00Z' + commission: + type: object + properties: + rate: + type: string + example: '0' + max_rate: + type: string + example: '0' + max_change_rate: + type: string + example: '0' + update_time: + type: string + example: '1970-01-01T00:00:00Z' + Delegation: + type: object + properties: + delegator_addr: + type: string + validator_addr: + type: string + shares: + type: string + height: + type: integer + UnbondingDelegation: + type: object + properties: + delegator_addr: + type: string + validator_addr: + type: string + initial_balance: + type: string + balance: + type: string + creation_height: + type: integer + min_time: + type: integer + Redelegation: + type: object + properties: + delegator_addr: + type: string + validator_src_addr: + type: string + validator_dst_addr: + type: string + creation_height: + type: integer + min_time: + type: integer + initial_balance: + type: string + balance: + type: string + shares_src: + type: string + shares_dst: + type: string diff --git a/client/rpc/block.go b/client/rpc/block.go index 1090fd2d25d9..b2db545dbdd1 100644 --- a/client/rpc/block.go +++ b/client/rpc/block.go @@ -115,19 +115,19 @@ func BlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { vars := mux.Vars(r) height, err := strconv.ParseInt(vars["height"], 10, 64) if err != nil { - w.WriteHeader(400) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/block/{height}'.")) return } chainHeight, err := GetChainHeight(cliCtx) if height > chainHeight { - w.WriteHeader(404) + w.WriteHeader(http.StatusNotFound) w.Write([]byte("ERROR: Requested block height is bigger then the chain length.")) return } output, err := getBlock(cliCtx, &height) if err != nil { - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } @@ -140,13 +140,13 @@ func LatestBlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { height, err := GetChainHeight(cliCtx) if err != nil { - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } output, err := getBlock(cliCtx, &height) if err != nil { - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } diff --git a/client/rpc/status.go b/client/rpc/status.go index 7f3494216024..68716f3a0b75 100644 --- a/client/rpc/status.go +++ b/client/rpc/status.go @@ -69,7 +69,7 @@ func NodeInfoRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { status, err := getNodeStatus(cliCtx) if err != nil { - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } @@ -84,14 +84,14 @@ func NodeSyncingRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { status, err := getNodeStatus(cliCtx) if err != nil { - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } syncing := status.SyncInfo.CatchingUp if err != nil { - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } diff --git a/client/rpc/validators.go b/client/rpc/validators.go index fc37881cba92..330966bf874f 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -140,21 +140,21 @@ func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { height, err := strconv.ParseInt(vars["height"], 10, 64) if err != nil { - w.WriteHeader(400) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/validatorsets/{height}'.")) return } chainHeight, err := GetChainHeight(cliCtx) if height > chainHeight { - w.WriteHeader(404) + w.WriteHeader(http.StatusNotFound) w.Write([]byte("ERROR: Requested block height is bigger then the chain length.")) return } output, err := getValidators(cliCtx, &height) if err != nil { - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } @@ -167,14 +167,14 @@ func LatestValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerF return func(w http.ResponseWriter, r *http.Request) { height, err := GetChainHeight(cliCtx) if err != nil { - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } output, err := getValidators(cliCtx, &height) if err != nil { - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } diff --git a/client/utils/rest.go b/client/utils/rest.go index b74b91d035cf..e9d948514720 100644 --- a/client/utils/rest.go +++ b/client/utils/rest.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" @@ -229,9 +230,15 @@ func CompleteAndBroadcastTxREST(w http.ResponseWriter, r *http.Request, cliCtx c } txBytes, err := txBldr.BuildAndSign(baseReq.Name, baseReq.Password, msgs) - if err != nil { + if keyerror.IsErrKeyNotFound(err) { + WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } else if keyerror.IsErrWrongPassword(err) { WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) return + } else if err != nil { + WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return } res, err := cliCtx.BroadcastTx(txBytes) diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index b75c3473ba81..ad43bfd9f4ab 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -19,6 +19,7 @@ import ( "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/crypto/secp256k1" dbm "github.com/tendermint/tendermint/libs/db" + "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" ) var _ Keybase = dbKeybase{} @@ -217,7 +218,7 @@ func (kb dbKeybase) List() ([]Info, error) { func (kb dbKeybase) Get(name string) (Info, error) { bs := kb.db.Get(infoKey(name)) if len(bs) == 0 { - return nil, fmt.Errorf("Key %s not found", name) + return nil, keyerror.NewErrKeyNotFound(name) } return readInfo(bs) } diff --git a/crypto/keys/keyerror/errors.go b/crypto/keys/keyerror/errors.go new file mode 100644 index 000000000000..1042689e3891 --- /dev/null +++ b/crypto/keys/keyerror/errors.go @@ -0,0 +1,81 @@ +package keyerror + +import ( + "fmt" +) + +const ( + codeKeyNotFound = 1 + codeWrongPassword = 2 +) + +type keybaseError interface { + error + Code() int +} + +type errKeyNotFound struct { + code int + name string +} + +func (e errKeyNotFound) Code() int { + return e.code +} + +func (e errKeyNotFound) Error() string { + return fmt.Sprintf("Key %s not found", e.name) +} + +// NewErrKeyNotFound returns a standardized error reflecting that the specified key doesn't exist +func NewErrKeyNotFound(name string) error { + return errKeyNotFound{ + code: codeKeyNotFound, + name: name, + } +} + +// IsErrKeyNotFound returns true if the given error is errKeyNotFound +func IsErrKeyNotFound(err error) bool { + if err == nil { + return false + } + if keyErr, ok := err.(keybaseError); ok { + if keyErr.Code() == codeKeyNotFound { + return true + } + } + return false +} + +type errWrongPassword struct { + code int +} + +func (e errWrongPassword) Code() int { + return e.code +} + +func (e errWrongPassword) Error() string { + return fmt.Sprintf("Ciphertext decryption failed") +} + +// NewErrWrongPassword returns a standardized error reflecting that the specified password is wrong +func NewErrWrongPassword() error { + return errWrongPassword{ + code: codeWrongPassword, + } +} + +// IsErrWrongPassword returns true if the given error is errWrongPassword +func IsErrWrongPassword(err error) bool { + if err == nil { + return false + } + if keyErr, ok := err.(keybaseError); ok { + if keyErr.Code() == codeWrongPassword { + return true + } + } + return false +} diff --git a/crypto/keys/mintkey/mintkey.go b/crypto/keys/mintkey/mintkey.go index 80377920fe46..20a183f33074 100644 --- a/crypto/keys/mintkey/mintkey.go +++ b/crypto/keys/mintkey/mintkey.go @@ -12,6 +12,7 @@ import ( "github.com/tendermint/tendermint/crypto/xsalsa20symmetric" cmn "github.com/tendermint/tendermint/libs/common" + "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" ) const ( @@ -144,7 +145,9 @@ func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privK } key = crypto.Sha256(key) // Get 32 bytes privKeyBytes, err := xsalsa20symmetric.DecryptSymmetric(encBytes, key) - if err != nil { + if err != nil && err.Error() == "Ciphertext decryption failed" { + return privKey, keyerror.NewErrWrongPassword() + } else if err != nil { return privKey, err } privKey, err = cryptoAmino.PrivKeyFromBytes(privKeyBytes) diff --git a/x/auth/client/rest/sign.go b/x/auth/client/rest/sign.go index 9e9b92b5ade1..4a257ff6c666 100644 --- a/x/auth/client/rest/sign.go +++ b/x/auth/client/rest/sign.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/auth" authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" + "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" ) // SignBody defines the properties of a sign request's body. @@ -47,7 +48,13 @@ func SignTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha } signedTx, err := txBldr.SignStdTx(m.LocalAccountName, m.Password, m.Tx, m.AppendSig) - if err != nil { + if keyerror.IsErrKeyNotFound(err) { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } else if keyerror.IsErrWrongPassword(err) { + utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) + return + } else if err != nil { utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index a06cf58460da..7bb2640fddfd 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -56,7 +56,7 @@ func SendRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIC info, err := kb.Get(baseReq.Name) if err != nil { - utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 23e95105e0ed..eebcda882faf 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -17,6 +17,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/x/gov/client" ) const ( @@ -115,7 +116,7 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome cmd.Flags().String(flagTitle, "", "title of proposal") cmd.Flags().String(flagDescription, "", "description of proposal") - cmd.Flags().String(flagProposalType, "", "proposalType of proposal") + cmd.Flags().String(flagProposalType, "", "proposalType of proposal, types: text/parameter_change/software_upgrade") cmd.Flags().String(flagDeposit, "", "deposit of proposal") cmd.Flags().String(flagProposal, "", "proposal file path (if this path is given, other proposal flags are ignored)") @@ -129,7 +130,7 @@ func parseSubmitProposalFlags() (*proposal, error) { if proposalFile == "" { proposal.Title = viper.GetString(flagTitle) proposal.Description = viper.GetString(flagDescription) - proposal.Type = viper.GetString(flagProposalType) + proposal.Type = client.NormalizeProposalType(viper.GetString(flagProposalType)) proposal.Deposit = viper.GetString(flagDeposit) return proposal, nil } @@ -202,7 +203,7 @@ func GetCmdDeposit(cdc *codec.Codec) *cobra.Command { func GetCmdVote(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "vote", - Short: "Vote for an active proposal, options: Yes/No/NoWithVeto/Abstain", + Short: "Vote for an active proposal, options: yes/no/no_with_veto/abstain", RunE: func(cmd *cobra.Command, args []string) error { txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc) cliCtx := context.NewCLIContext(). @@ -217,7 +218,7 @@ func GetCmdVote(cdc *codec.Codec) *cobra.Command { proposalID := viper.GetInt64(flagProposalID) option := viper.GetString(flagOption) - byteVoteOption, err := gov.VoteOptionFromString(option) + byteVoteOption, err := gov.VoteOptionFromString(client.NormalizeVoteOption(option)) if err != nil { return err } @@ -243,7 +244,7 @@ func GetCmdVote(cdc *codec.Codec) *cobra.Command { } cmd.Flags().String(flagProposalID, "", "proposalID of proposal voting on") - cmd.Flags().String(flagOption, "", "vote option {Yes, No, NoWithVeto, Abstain}") + cmd.Flags().String(flagOption, "", "vote option {yes, no, no_with_veto, abstain}") return cmd } @@ -313,7 +314,7 @@ func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command { } if len(strProposalStatus) != 0 { - proposalStatus, err := gov.ProposalStatusFromString(strProposalStatus) + proposalStatus, err := gov.ProposalStatusFromString(client.NormalizeProposalStatus(strProposalStatus)) if err != nil { return err } @@ -354,7 +355,7 @@ func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command { cmd.Flags().String(flagLatestProposalIDs, "", "(optional) limit to latest [number] proposals. Defaults to all proposals") cmd.Flags().String(flagDepositer, "", "(optional) filter by proposals deposited on by depositer") cmd.Flags().String(flagVoter, "", "(optional) filter by proposals voted on by voted") - cmd.Flags().String(flagStatus, "", "(optional) filter proposals by proposal status") + cmd.Flags().String(flagStatus, "", "(optional) filter proposals by proposal status, status: deposit_period/voting_period/passed/rejected") return cmd } diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 5ed12ac700ae..882dcf0e1b55 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -12,12 +12,13 @@ import ( "github.com/gorilla/mux" "github.com/pkg/errors" + "github.com/cosmos/cosmos-sdk/x/gov/client" ) // REST Variable names // nolint const ( - RestProposalID = "proposal-id" + RestProposalID = "proposalId" RestDepositer = "depositer" RestVoter = "voter" RestProposalStatus = "status" @@ -43,7 +44,7 @@ type postProposalReq struct { BaseReq utils.BaseReq `json:"base_req"` Title string `json:"title"` // Title of the proposal Description string `json:"description"` // Description of the proposal - ProposalType gov.ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal} + ProposalType string `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal} Proposer sdk.AccAddress `json:"proposer"` // Address of the proposer InitialDeposit sdk.Coins `json:"initial_deposit"` // Coins to add to the proposal's deposit } @@ -57,7 +58,7 @@ type depositReq struct { type voteReq struct { BaseReq utils.BaseReq `json:"base_req"` Voter sdk.AccAddress `json:"voter"` // address of the voter - Option gov.VoteOption `json:"option"` // option from OptionSet chosen by the voter + Option string `json:"option"` // option from OptionSet chosen by the voter } func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc { @@ -65,6 +66,7 @@ func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han var req postProposalReq err := utils.ReadRESTReq(w, r, cdc, &req) if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -73,8 +75,14 @@ func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han return } + proposalType, err := gov.ProposalTypeFromString(client.NormalizeProposalType(req.ProposalType)) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + // create the message - msg := gov.NewMsgSubmitProposal(req.Title, req.Description, req.ProposalType, req.Proposer, req.InitialDeposit) + msg := gov.NewMsgSubmitProposal(req.Title, req.Description, proposalType, req.Proposer, req.InitialDeposit) err = msg.ValidateBasic() if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) @@ -151,8 +159,14 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc return } + voteOption, err := gov.VoteOptionFromString(client.NormalizeVoteOption(req.Option)) + if err != nil { + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + // create the message - msg := gov.NewMsgVote(req.Voter, proposalID, req.Option) + msg := gov.NewMsgVote(req.Voter, proposalID, voteOption) err = msg.ValidateBasic() if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) @@ -391,6 +405,7 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } + utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) } } @@ -424,7 +439,7 @@ func queryProposalsWithParameterFn(cdc *codec.Codec, cliCtx context.CLIContext) } if len(strProposalStatus) != 0 { - proposalStatus, err := gov.ProposalStatusFromString(strProposalStatus) + proposalStatus, err := gov.ProposalStatusFromString(client.NormalizeProposalStatus(strProposalStatus)) if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return @@ -450,6 +465,7 @@ func queryProposalsWithParameterFn(cdc *codec.Codec, cliCtx context.CLIContext) utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } + utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) } } @@ -489,6 +505,7 @@ func queryTallyOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) w.Write([]byte(err.Error())) return } + utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) } } diff --git a/x/gov/client/utils.go b/x/gov/client/utils.go new file mode 100644 index 000000000000..8dcde5c62e97 --- /dev/null +++ b/x/gov/client/utils.go @@ -0,0 +1,45 @@ +package client + +// NormalizeVoteOption - normalize user specified vote option +func NormalizeVoteOption(option string) string { + switch option { + case "Yes", "yes": + return "Yes" + case "Abstain", "abstain": + return "Abstain" + case "No", "no": + return "No" + case "NoWithVeto", "no_with_veto": + return "NoWithVeto" + } + return "" +} + +//NormalizeProposalType - normalize user specified proposal type +func NormalizeProposalType(proposalType string) string { + switch proposalType { + case "Text", "text": + return "Text" + case "ParameterChange", "parameter_change": + return "ParameterChange" + case "SoftwareUpgrade", "software_upgrade": + return "SoftwareUpgrade" + } + return "" +} + +//NormalizeProposalStatus - normalize user specified proposal status +func NormalizeProposalStatus(status string) string { + switch status { + case "DepositPeriod", "deposit_period": + return "DepositPeriod" + case "VotingPeriod", "voting_period": + return "VotingPeriod" + case "Passed", "passed": + return "Passed" + case "Rejected", "rejected": + return "Rejected" + } + return "" +} + diff --git a/x/slashing/client/rest/query.go b/x/slashing/client/rest/query.go index 408b1f592643..8beab13adfbf 100644 --- a/x/slashing/client/rest/query.go +++ b/x/slashing/client/rest/query.go @@ -4,16 +4,16 @@ import ( "net/http" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/gorilla/mux" + "github.com/cosmos/cosmos-sdk/client/utils" ) func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec) { r.HandleFunc( - "/slashing/signing_info/{validator}", + "/slashing/validators/{validatorPubKey}/signing_info", signingInfoHandlerFn(cliCtx, "slashing", cdc), ).Methods("GET") } @@ -24,7 +24,7 @@ func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *code return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - pk, err := sdk.GetConsPubKeyBech32(vars["validator"]) + pk, err := sdk.GetConsPubKeyBech32(vars["validatorPubKey"]) if err != nil { utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return @@ -38,21 +38,19 @@ func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *code return } - var signingInfo slashing.ValidatorSigningInfo - - err = cdc.UnmarshalBinary(res, &signingInfo) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + if len(res) == 0 { + w.WriteHeader(http.StatusNoContent) return } - output, err := cdc.MarshalJSON(signingInfo) + var signingInfo slashing.ValidatorSigningInfo + + err = cdc.UnmarshalBinary(res, &signingInfo) if err != nil { utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - w.Header().Set("Content-Type", "application/json") - w.Write(output) + utils.PostProcessResponse(w, cdc, signingInfo, cliCtx.Indent) } } diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index eca88c65cdbd..3059fe4c35f8 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -16,7 +16,7 @@ import ( func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, kb keys.Keybase) { r.HandleFunc( - "/slashing/unjail", + "/slashing/validators/{validatorAddr}/unjail", unjailRequestHandlerFn(cdc, kb, cliCtx), ).Methods("POST") } @@ -24,11 +24,14 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec // Unjail TX body type UnjailReq struct { BaseReq utils.BaseReq `json:"base_req"` - ValidatorAddr string `json:"validator_addr"` } func unjailRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + bech32validator := vars["validatorAddr"] + var req UnjailReq err := utils.ReadRESTReq(w, r, cdc, &req) if err != nil { @@ -46,7 +49,7 @@ func unjailRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CL return } - valAddr, err := sdk.ValAddressFromBech32(req.ValidatorAddr) + valAddr, err := sdk.ValAddressFromBech32(bech32validator) if err != nil { utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index e4fd6a1a38a7..437d40e77814 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -262,12 +262,6 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte results[i] = res } - res, err := codec.MarshalJSONIndent(cdc, results[:]) - if err != nil { - utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) + utils.PostProcessResponse(w, cdc, results, cliCtx.Indent) } }