Merge PR #2365: Validator Commission Model

* Update validator commission fields

* Remove CommissionChangeToday and update to use CommissionChangeTime

* Implement commission as a first class citizen type

* Implement stringer for Comission

* Move commission type and logic to new  file

* Add new commission errors

* Add commission to create validator message

* Implement and call UpdateValidatorCommission

* Update godoc for UpdateValidatorCommission

* Add Abs to the decimal type

* Implement new SetValidatorCommission

* Update decimal short godocs

* Move set initial commission logic

* Move initial commission validation to Commission type

* Update initial validator commission logic and unit tests

* Remove commission update time from struct and move to validator

* Update validator create handler tests

* Implement commission logic for CLI

* Fix make lint failure

* Fix make cover failure

* Update edit validator logic to handle new commission rate

* Fix lint and cover

* Update create/edit validator simulation to include commission params

* Update MsgEditValidator godoc

* Update pending log

* Update staking tx docs

* Fix CLI create validator test

* Update variables names for commission  strings

* Merge UpdateTime into Commission type

* Update create-validator usage in docs

* Update more docs with examples

* More doc updates
This commit is contained in:
Alexander Bezobchuk
2018-09-24 18:23:58 -04:00
committed by Rigel
parent 8774adc7de
commit 9dafa3252d
25 changed files with 728 additions and 282 deletions
+10
View File
@@ -21,6 +21,10 @@ const (
FlagIdentity = "identity"
FlagWebsite = "website"
FlagDetails = "details"
FlagCommissionRate = "commission-rate"
FlagCommissionMaxRate = "commission-max-rate"
FlagCommissionMaxChangeRate = "commission-max-change-rate"
)
// common flagsets to add to various functions
@@ -29,6 +33,8 @@ var (
fsAmount = flag.NewFlagSet("", flag.ContinueOnError)
fsShares = flag.NewFlagSet("", flag.ContinueOnError)
fsDescriptionCreate = flag.NewFlagSet("", flag.ContinueOnError)
fsCommissionCreate = flag.NewFlagSet("", flag.ContinueOnError)
fsCommissionUpdate = flag.NewFlagSet("", flag.ContinueOnError)
fsDescriptionEdit = flag.NewFlagSet("", flag.ContinueOnError)
fsValidator = flag.NewFlagSet("", flag.ContinueOnError)
fsDelegator = flag.NewFlagSet("", flag.ContinueOnError)
@@ -44,6 +50,10 @@ func init() {
fsDescriptionCreate.String(FlagIdentity, "", "optional identity signature (ex. UPort or Keybase)")
fsDescriptionCreate.String(FlagWebsite, "", "optional website")
fsDescriptionCreate.String(FlagDetails, "", "optional details")
fsCommissionUpdate.String(FlagCommissionRate, "", "The new commission rate percentage")
fsCommissionCreate.String(FlagCommissionRate, "", "The initial commission rate percentage")
fsCommissionCreate.String(FlagCommissionMaxRate, "", "The maximum commission rate percentage")
fsCommissionCreate.String(FlagCommissionMaxChangeRate, "", "The maximum commission change rate percentage (per day)")
fsDescriptionEdit.String(FlagMoniker, types.DoNotModifyDesc, "validator name")
fsDescriptionEdit.String(FlagIdentity, types.DoNotModifyDesc, "optional identity signature (ex. UPort or Keybase)")
fsDescriptionEdit.String(FlagWebsite, types.DoNotModifyDesc, "optional website")
+33 -53
View File
@@ -12,9 +12,7 @@ import (
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@@ -66,6 +64,15 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
Details: viper.GetString(FlagDetails),
}
// get the initial validator commission parameters
rateStr := viper.GetString(FlagCommissionRate)
maxRateStr := viper.GetString(FlagCommissionMaxRate)
maxChangeRateStr := viper.GetString(FlagCommissionMaxChangeRate)
commissionMsg, err := buildCommissionMsg(rateStr, maxRateStr, maxChangeRateStr)
if err != nil {
return err
}
var msg sdk.Msg
if viper.GetString(FlagAddressDelegator) != "" {
delAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator))
@@ -73,13 +80,19 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
return err
}
msg = stake.NewMsgCreateValidatorOnBehalfOf(delAddr, sdk.ValAddress(valAddr), pk, amount, description)
msg = stake.NewMsgCreateValidatorOnBehalfOf(
delAddr, sdk.ValAddress(valAddr), pk, amount, description, commissionMsg,
)
} else {
msg = stake.NewMsgCreateValidator(sdk.ValAddress(valAddr), pk, amount, description)
msg = stake.NewMsgCreateValidator(
sdk.ValAddress(valAddr), pk, amount, description, commissionMsg,
)
}
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
}
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
},
@@ -88,6 +101,7 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
cmd.Flags().AddFlagSet(fsPk)
cmd.Flags().AddFlagSet(fsAmount)
cmd.Flags().AddFlagSet(fsDescriptionCreate)
cmd.Flags().AddFlagSet(fsCommissionCreate)
cmd.Flags().AddFlagSet(fsDelegator)
return cmd
@@ -117,17 +131,31 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command {
Details: viper.GetString(FlagDetails),
}
msg := stake.NewMsgEditValidator(sdk.ValAddress(valAddr), description)
var newRate *sdk.Dec
commissionRate := viper.GetString(FlagCommissionRate)
if commissionRate != "" {
rate, err := sdk.NewDecFromStr(commissionRate)
if err != nil {
return fmt.Errorf("invalid new commission rate: %v", err)
}
newRate = &rate
}
msg := stake.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate)
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
}
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
},
}
cmd.Flags().AddFlagSet(fsDescriptionEdit)
cmd.Flags().AddFlagSet(fsCommissionUpdate)
return cmd
}
@@ -247,54 +275,6 @@ func GetCmdBeginRedelegate(storeName string, cdc *codec.Codec) *cobra.Command {
return cmd
}
// nolint: gocyclo
// TODO: Make this pass gocyclo linting
func getShares(
storeName string, cdc *codec.Codec, sharesAmountStr,
sharesPercentStr string, delAddr sdk.AccAddress, valAddr sdk.ValAddress,
) (sharesAmount sdk.Dec, err error) {
switch {
case sharesAmountStr != "" && sharesPercentStr != "":
return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both")
case sharesAmountStr == "" && sharesPercentStr == "":
return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both")
case sharesAmountStr != "":
sharesAmount, err = sdk.NewDecFromStr(sharesAmountStr)
if err != nil {
return sharesAmount, err
}
if !sharesAmount.GT(sdk.ZeroDec()) {
return sharesAmount, errors.Errorf("shares amount must be positive number (ex. 123, 1.23456789)")
}
case sharesPercentStr != "":
var sharesPercent sdk.Dec
sharesPercent, err = sdk.NewDecFromStr(sharesPercentStr)
if err != nil {
return sharesAmount, err
}
if !sharesPercent.GT(sdk.ZeroDec()) || !sharesPercent.LTE(sdk.OneDec()) {
return sharesAmount, errors.Errorf("shares percent must be >0 and <=1 (ex. 0.01, 0.75, 1)")
}
// make a query to get the existing delegation shares
key := stake.GetDelegationKey(delAddr, valAddr)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
resQuery, err := cliCtx.QueryStore(key, storeName)
if err != nil {
return sharesAmount, errors.Errorf("cannot find delegation to determine percent Error: %v", err)
}
delegation, err := types.UnmarshalDelegation(cdc, key, resQuery)
if err != nil {
return sdk.ZeroDec(), err
}
sharesAmount = sharesPercent.Mul(delegation.Shares)
}
return
}
// GetCmdCompleteRedelegate implements the complete redelegation command.
func GetCmdCompleteRedelegate(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
+88
View File
@@ -0,0 +1,88 @@
package cli
import (
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/pkg/errors"
)
func getShares(
storeName string, cdc *codec.Codec, sharesAmountStr,
sharesPercentStr string, delAddr sdk.AccAddress, valAddr sdk.ValAddress,
) (sharesAmount sdk.Dec, err error) {
switch {
case sharesAmountStr != "" && sharesPercentStr != "":
return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both")
case sharesAmountStr == "" && sharesPercentStr == "":
return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both")
case sharesAmountStr != "":
sharesAmount, err = sdk.NewDecFromStr(sharesAmountStr)
if err != nil {
return sharesAmount, err
}
if !sharesAmount.GT(sdk.ZeroDec()) {
return sharesAmount, errors.Errorf("shares amount must be positive number (ex. 123, 1.23456789)")
}
case sharesPercentStr != "":
var sharesPercent sdk.Dec
sharesPercent, err = sdk.NewDecFromStr(sharesPercentStr)
if err != nil {
return sharesAmount, err
}
if !sharesPercent.GT(sdk.ZeroDec()) || !sharesPercent.LTE(sdk.OneDec()) {
return sharesAmount, errors.Errorf("shares percent must be >0 and <=1 (ex. 0.01, 0.75, 1)")
}
// make a query to get the existing delegation shares
key := stake.GetDelegationKey(delAddr, valAddr)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
resQuery, err := cliCtx.QueryStore(key, storeName)
if err != nil {
return sharesAmount, errors.Errorf("cannot find delegation to determine percent Error: %v", err)
}
delegation, err := types.UnmarshalDelegation(cdc, key, resQuery)
if err != nil {
return sdk.ZeroDec(), err
}
sharesAmount = sharesPercent.Mul(delegation.Shares)
}
return
}
func buildCommissionMsg(rateStr, maxRateStr, maxChangeRateStr string) (commission types.CommissionMsg, err error) {
if rateStr == "" || maxRateStr == "" || maxChangeRateStr == "" {
return commission, errors.Errorf("must specify all validator commission parameters")
}
rate, err := sdk.NewDecFromStr(rateStr)
if err != nil {
return commission, err
}
maxRate, err := sdk.NewDecFromStr(maxRateStr)
if err != nil {
return commission, err
}
maxChangeRate, err := sdk.NewDecFromStr(maxChangeRateStr)
if err != nil {
return commission, err
}
commission = types.NewCommissionMsg(rate, maxRate, maxChangeRate)
return commission, nil
}