Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: Implement fee distribution RESTful endpoints #3460

Merged
merged 29 commits into from
Feb 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d14e919
Factor params query logic out
Jan 30, 2019
9dc2199
REST skeleton
Jan 30, 2019
14f1b07
Start working on params query
Jan 30, 2019
27a8f2c
Implement pool endpoint and querier
Jan 31, 2019
4eac5e8
Implement GET /distribution/delegators/{delegatorAddr}/rewards
Jan 31, 2019
d5939a1
Add delegation query
Jan 31, 2019
50bf781
Refactor, make new client common sub-package
Jan 31, 2019
71d2898
Implement GET /distribution/delegators/{delegatorAddr}/withdraw_address
Jan 31, 2019
effc2e9
WIP, issue is blocked
Feb 1, 2019
094aa52
Update distribution swagger.yaml section for F1
cwgoes Feb 1, 2019
009e927
Replace pool with outstanding_rewards
Feb 1, 2019
fd26e55
Finalize query endpoints
Feb 1, 2019
be16e5c
Implement POST /delegators/{delegatorAddr}/rewards/{validatorAddr}
Feb 4, 2019
9e9e665
Implement /validators/{validatorAddr}/rewards
Feb 1, 2019
32811f9
Factour out logic to prepare multi-msg withdrawal
Feb 1, 2019
1d5cf3f
WIP
Feb 2, 2019
f12c772
all_delegation_rewards -> total_delegation_rewards
Feb 4, 2019
834dd56
rigel/distr-queriers
Feb 4, 2019
bbc8f99
Implement /delegators/{delegatorAddr}/rewards
Feb 2, 2019
bb8767d
Implement cli withdraw-all-rewards command as multi-message tx
Feb 2, 2019
ec34237
Implement /delegators/{delegatorAddr}/withdraw_address
Feb 2, 2019
20826e8
invert abort with ok
Feb 2, 2019
4e23cf3
Clean up
Feb 2, 2019
a285f10
Update PENDING.md
Feb 4, 2019
0e9504c
Clean up rebase leftover, port to new rest package
Feb 4, 2019
d18d7eb
Don't write errors twice when ReadRESTReq() fails
Feb 4, 2019
4291cbe
Update PENDING.md
Feb 4, 2019
045d9f4
Split up QueryRewards
Feb 4, 2019
09239a9
Add tests
Feb 4, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ BREAKING CHANGES
* [\#3284](https://github.com/cosmos/cosmos-sdk/issues/3284) Rename the `name`
field to `from` in the `base_req` body.
* [\#3485](https://github.com/cosmos/cosmos-sdk/pull/3485) Error responses are now JSON objects.
* [\#3477][distribution] endpoint changed "all_delegation_rewards" -> "delegator_total_rewards"

* Gaia CLI (`gaiacli`)
- [#3399](https://github.com/cosmos/cosmos-sdk/pull/3399) Add `gaiad validate-genesis` command to facilitate checking of genesis files
Expand All @@ -18,13 +19,15 @@ BREAKING CHANGES

* SDK
* [\#3487](https://github.com/cosmos/cosmos-sdk/pull/3487) Move HTTP/REST utilities out of client/utils into a new dedicated client/rest package.
* [\#3490](https://github.com/cosmos/cosmos-sdk/issues/3490) ReadRESTReq() returns bool to avoid callers to write error responses twice.

* Tendermint


FEATURES

* Gaia REST API
* [\#2358](https://github.com/cosmos/cosmos-sdk/issues/2358) Add distribution module REST interface

* Gaia CLI (`gaiacli`)
* [\#3429](https://github.com/cosmos/cosmos-sdk/issues/3429) Support querying
Expand All @@ -37,6 +40,7 @@ FEATURES

* SDK
* \#3270 [x/staking] limit number of ongoing unbonding delegations /redelegations per pair/trio
* [\#3477][distribution] new query endpoint "delegator_validators"

* Tendermint

Expand All @@ -53,6 +57,7 @@ IMPROVEMENTS
(auto gas) to work with generate only.

* Gaia CLI (`gaiacli`)
* [\#3476](https://github.com/cosmos/cosmos-sdk/issues/3476) New `withdraw-all-rewards` command to withdraw all delegations rewards for delegators.

* Gaia
* [\#3418](https://github.com/cosmos/cosmos-sdk/issues/3418) Add vesting account
Expand Down
98 changes: 98 additions & 0 deletions client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/bank"
dclcommon "github.com/cosmos/cosmos-sdk/x/distribution/client/common"
distrrest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
Expand Down Expand Up @@ -914,3 +916,99 @@ func TestSlashingGetParams(t *testing.T) {
err := cdc.UnmarshalJSON([]byte(body), &params)
require.NoError(t, err)
}

func TestDistributionGetParams(t *testing.T) {
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{})
defer cleanup()

res, body := Request(t, port, "GET", "/distribution/parameters", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &dclcommon.PrettyParams{}))
}

func TestDistributionFlow(t *testing.T) {
addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t))
//addr2, seed2 = CreateAddr(t, name2, pw, GetKeyBase(t))
cleanup, _, valAddrs, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()

valAddr := valAddrs[0]
operAddr := sdk.AccAddress(valAddr)

var rewards sdk.DecCoins
res, body := Request(t, port, "GET", fmt.Sprintf("/distribution/outstanding_rewards"), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, sdk.DecCoins(nil), rewards)

var valDistInfo distrrest.ValidatorDistInfo
res, body = Request(t, port, "GET", "/distribution/validators/"+valAddr.String(), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &valDistInfo))
require.Equal(t, valDistInfo.OperatorAddress.String(), sdk.AccAddress(valAddr).String())
require.Equal(t, valDistInfo.ValidatorCommission, sdk.DecCoins(nil))
require.Equal(t, valDistInfo.SelfBondRewards, sdk.DecCoins(nil))

// Delegate some coins
resultTx := doDelegate(t, port, name1, pw, addr, valAddr, 60, fees)
tests.WaitForHeight(resultTx.Height+1, port)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)

// send some coins
_, resultTx = doTransfer(t, port, seed, name1, memo, pw, addr, fees)
tests.WaitForHeight(resultTx.Height+5, port)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)

// Query outstanding rewards changed
oustandingRewards := mustParseDecCoins("9.80stake")
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/outstanding_rewards"), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, oustandingRewards, rewards)

// Query validator distribution info
res, body = Request(t, port, "GET", "/distribution/validators/"+valAddr.String(), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)

valRewards := mustParseDecCoins("6.125stake")
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &valDistInfo))
require.Equal(t, valRewards, valDistInfo.SelfBondRewards)

// Query validator's rewards
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/validators/%s/rewards", valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, valRewards, rewards)

// Query self-delegation
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/delegators/%s/rewards/%s", operAddr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, valRewards, rewards)

// Query delegation
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/delegators/%s/rewards/%s", addr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, mustParseDecCoins("3.675stake"), rewards)

// Query delegator's rewards total
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/delegators/%s/rewards", operAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
require.Equal(t, valRewards, rewards)

// Query delegator's withdrawal address
var withdrawAddr string
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/delegators/%s/withdraw_address", operAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &withdrawAddr))
require.Equal(t, operAddr.String(), withdrawAddr)

// Withdraw delegator's rewards
resultTx = doWithdrawDelegatorAllRewards(t, port, seed, name1, pw, addr, fees)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
}
38 changes: 8 additions & 30 deletions client/lcd/swagger-ui/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ tags:
- name: ICS23
description: Slashing module APIs
- name: ICS24
description: WIP - Fee distribution module APIs
description: Fee distribution module APIs
- name: version
description: Query app version
schemes:
Expand Down Expand Up @@ -1846,9 +1846,9 @@ paths:
type: string
500:
description: Internal Server Error
/distribution/pool:
/distribution/outstanding_rewards:
get:
summary: Fee distribution pool
summary: Fee distribution outstanding rewards
tags:
- ICS24
produces:
Expand All @@ -1857,7 +1857,9 @@ paths:
200:
description: OK
schema:
$ref: "#/definitions/FeePool"
type: array
items:
$ref: "#/definitions/Coin"
500:
description: Internal Server Error
definitions:
Expand Down Expand Up @@ -2198,7 +2200,7 @@ definitions:
power:
type: string
example: "1000"
accum:
proposer_priority:
type: string
example: "1000"
TextProposal:
Expand Down Expand Up @@ -2367,36 +2369,12 @@ definitions:
type: string
shares_dst:
type: string
FeePool:
type: object
properties:
community_pool:
type: array
items:
$ref: "#/definitions/Coin"
val_accum:
$ref: "#/definitions/TotalAccum"
val_pool:
type: array
items:
$ref: "#/definitions/Coin"
TotalAccum:
type: object
properties:
update_height:
type: integer
accum:
type: string
ValidatorDistInfo:
type: object
properties:
operator_addr:
$ref: "#/definitions/ValidatorAddress"
fee_pool_withdrawal_height:
type: integer
del_accum:
$ref: "#/definitions/TotalAccum"
del_pool:
self_bond_rewards:
type: array
items:
$ref: "#/definitions/Coin"
Expand Down
42 changes: 42 additions & 0 deletions client/lcd/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ import (

authRest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
bankRest "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
distrRest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
govRest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
slashingRest "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
stakingRest "github.com/cosmos/cosmos-sdk/x/staking/client/rest"
Expand Down Expand Up @@ -294,6 +296,11 @@ func InitializeTestLCD(
genesisState.StakingData.Pool.NotBondedTokens = genesisState.StakingData.Pool.NotBondedTokens.Add(sdk.NewInt(100))
}

inflationMin := sdk.MustNewDecFromStr("10000.0")
genesisState.MintData.Minter.Inflation = inflationMin
genesisState.MintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0")
genesisState.MintData.Params.InflationMin = inflationMin

appState, err := codec.MarshalJSONIndent(cdc, genesisState)
require.NoError(t, err)
genDoc.AppState = appState
Expand Down Expand Up @@ -390,6 +397,7 @@ func registerRoutes(rs *RestServer) {
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
authRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, auth.StoreKey)
bankRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
distrRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, distr.StoreKey)
stakingRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
slashingRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
govRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
Expand Down Expand Up @@ -1382,3 +1390,37 @@ func doUnjail(t *testing.T, port, seed, name, password string,
type unjailReq struct {
BaseReq rest.BaseReq `json:"base_req"`
}

// ICS24 - fee distribution

// POST /distribution/delegators/{delgatorAddr}/rewards Withdraw delegator rewards
func doWithdrawDelegatorAllRewards(t *testing.T, port, seed, name, password string,
delegatorAddr sdk.AccAddress, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) {
// get the account to get the sequence
acc := getAccount(t, port, delegatorAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)

wr := struct {
BaseReq rest.BaseReq `json:"base_req"`
}{BaseReq: baseReq}

req := cdc.MustMarshalJSON(wr)
res, body := Request(t, port, "POST", fmt.Sprintf("/distribution/delegators/%s/rewards", delegatorAddr), req)
require.Equal(t, http.StatusOK, res.StatusCode, body)

var results ctypes.ResultBroadcastTxCommit
cdc.MustUnmarshalJSON([]byte(body), &results)

return results
}

func mustParseDecCoins(dcstring string) sdk.DecCoins {
dcoins, err := sdk.ParseDecCoins(dcstring)
if err != nil {
panic(err)
}
return dcoins
}
14 changes: 8 additions & 6 deletions client/rest/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool {

/*
ReadRESTReq is a simple convenience wrapper that reads the body and
unmarshals to the req interface.
unmarshals to the req interface. Returns false if errors occurred.

Usage:
type SomeReq struct {
Expand All @@ -107,20 +107,22 @@ unmarshals to the req interface.
}

req := new(SomeReq)
err := ReadRESTReq(w, r, cdc, req)
if ok := ReadRESTReq(w, r, cdc, req); !ok {
return
}
*/
func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req interface{}) error {
func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req interface{}) bool {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return err
return false
}

err = cdc.UnmarshalJSON(body, req)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to decode JSON payload: %s", err))
return err
return false
}

return nil
return true
}
6 changes: 4 additions & 2 deletions cmd/gaia/cmd/gaiacli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
at "github.com/cosmos/cosmos-sdk/x/auth"
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
dist "github.com/cosmos/cosmos-sdk/x/distribution"
dist "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
gv "github.com/cosmos/cosmos-sdk/x/gov"
gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
sl "github.com/cosmos/cosmos-sdk/x/slashing"
Expand All @@ -35,6 +35,7 @@ import (

authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
distcmd "github.com/cosmos/cosmos-sdk/x/distribution"
distClient "github.com/cosmos/cosmos-sdk/x/distribution/client"
govClient "github.com/cosmos/cosmos-sdk/x/gov/client"
slashingClient "github.com/cosmos/cosmos-sdk/x/slashing/client"
Expand Down Expand Up @@ -65,7 +66,7 @@ func main() {
// TODO: Make the lcd command take a list of ModuleClient
mc := []sdk.ModuleClients{
govClient.NewModuleClient(gv.StoreKey, cdc),
distClient.NewModuleClient(dist.StoreKey, cdc),
distClient.NewModuleClient(distcmd.StoreKey, cdc),
stakingClient.NewModuleClient(st.StoreKey, cdc),
slashingClient.NewModuleClient(sl.StoreKey, cdc),
}
Expand Down Expand Up @@ -161,6 +162,7 @@ func registerRoutes(rs *lcd.RestServer) {
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, at.StoreKey)
bank.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
dist.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, distcmd.StoreKey)
staking.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
slashing.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
gov.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
Expand Down
3 changes: 1 addition & 2 deletions x/auth/client/rest/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ func SignTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha
return func(w http.ResponseWriter, r *http.Request) {
var m SignBody

if err := rest.ReadRESTReq(w, r, cdc, &m); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
if !rest.ReadRESTReq(w, r, cdc, &m) {
return
}

Expand Down
3 changes: 1 addition & 2 deletions x/bank/client/rest/sendtx.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ func SendRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIC
}

var req sendReq
err = rest.ReadRESTReq(w, r, cdc, &req)
if err != nil {
if !rest.ReadRESTReq(w, r, cdc, &req) {
return
}

Expand Down
Loading