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

[DFI-960] param changed hooks #12

Draft
wants to merge 3 commits into
base: dfinance/launchpad
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions x/params/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var (
NewParameterChangeProposal = types.NewParameterChangeProposal
NewParamChange = types.NewParamChange
ValidateChanges = types.ValidateChanges
NewMultiParamsHooks = types.NewMultiParamsHooks

// variable aliases
ModuleCdc = types.ModuleCdc
Expand All @@ -47,4 +48,6 @@ type (
ParamChange = types.ParamChange
RestrictedParams = types.RestrictedParams
RestrictedParam = types.RestrictedParam
MultiParamsHooks = types.MultiParamsHooks
ParametersHooks = types.ParamsHooks
)
31 changes: 31 additions & 0 deletions x/params/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ import (
"github.com/tendermint/tendermint/libs/log"
)

// Implements ParametersHooks interface
var _ types.ParamsHooks = Keeper{}

// Keeper of the global paramstore
type Keeper struct {
cdc *codec.Codec
key sdk.StoreKey
tkey sdk.StoreKey
spaces map[string]*Subspace
restrictedParams RestrictedParams
hooks ParametersHooks
}

// NewKeeper constructs a params keeper
Expand Down Expand Up @@ -77,3 +81,30 @@ func (k Keeper) CheckRestrictions(subspace, key string) error {

return nil
}

// AfterParamChanged - call hook after changed a parameter
func (k Keeper) AfterParamChanged(ctx sdk.Context, c ParamChange) error {
if k.hooks != nil {
return k.hooks.AfterParamChanged(ctx, c)
}

return nil
}

// BeforeParamChanged - call hook after changed a parameter
func (k Keeper) BeforeParamChanged(ctx sdk.Context, c ParamChange) error {
if k.hooks != nil {
return k.hooks.BeforeParamChanged(ctx, c)
}

return nil
}

// SetHooks sets hooks for call on the param update
func (k *Keeper) SetHooks(h ParametersHooks) *Keeper {
if k.hooks != nil {
panic("cannot set hooks twice")
}
k.hooks = h
return k
}
8 changes: 8 additions & 0 deletions x/params/proposal_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,17 @@ func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeP
fmt.Sprintf("attempt to set new parameter value; key: %s, value: %s", c.Key, c.Value),
)

if err := k.hooks.BeforeParamChanged(ctx, c); err != nil {
return sdkerrors.Wrapf(ErrSettingParameter, err.Error())
}

if err := ss.Update(ctx, []byte(c.Key), []byte(c.Value)); err != nil {
return sdkerrors.Wrapf(ErrSettingParameter, "key: %s, value: %s, err: %s", c.Key, c.Value, err.Error())
}

if err := k.hooks.AfterParamChanged(ctx, c); err != nil {
return sdkerrors.Wrapf(ErrSettingParameter, err.Error())
}
}

return nil
Expand Down
40 changes: 40 additions & 0 deletions x/params/types/hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package types

import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// ParamsHooks event hooks for params module
type ParamsHooks interface {
AfterParamChanged(ctx sdk.Context, c ParamChange) error
BeforeParamChanged(ctx sdk.Context, c ParamChange) error
}

type MultiParamsHooks []ParamsHooks

// NewMultiParamsHooks returns MultiParamsHooks container
func NewMultiParamsHooks(hooks ...ParamsHooks) MultiParamsHooks {
return hooks
}

// nolint
func (h MultiParamsHooks) AfterParamChanged(ctx sdk.Context, c ParamChange) error {
for i := range h {
if err := h[i].AfterParamChanged(ctx, c); err != nil {
return err
}
}

return nil
}

// nolint
func (h MultiParamsHooks) BeforeParamChanged(ctx sdk.Context, c ParamChange) error {
for i := range h {
if err := h[i].BeforeParamChanged(ctx, c); err != nil {
return err
}
}

return nil
}
1 change: 1 addition & 0 deletions x/staking/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ var (
ErrMaxDelegationsLimit = types.ErrMaxDelegationsLimit
ErrDeniedStakingOps = types.ErrDeniedStakingOps
ErrMaxSelfDelegationLimit = types.ErrMaxSelfDelegationLimit
ErrDeniedChangingParam = types.ErrDeniedChangingParam
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
NewMultiStakingHooks = types.NewMultiStakingHooks
Expand Down
93 changes: 93 additions & 0 deletions x/staking/keeper/param_hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package keeper

import (
"strconv"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/staking/types"
)

type ParamHooks struct {
k Keeper
}

var _ params.ParametersHooks = ParamHooks{}

func (k Keeper) ParamHooks() ParamHooks { return ParamHooks{k} }

// nolint:gocritic
// BeforeParamChanged Implements BeforeParamChanged
func (h ParamHooks) BeforeParamChanged(ctx sdk.Context, c params.ParamChange) (err error) {
if c.Subspace == DefaultParamspace {
switch c.Key {
case string(types.KeyMaxValidators):
err = beforeChangedMaxValidators(ctx, h.k, c)
}
}

return
}

// nolint:gocritic
// AfterParamChanged Implements AfterParamChanged
func (h ParamHooks) AfterParamChanged(ctx sdk.Context, c params.ParamChange) (err error) {
if c.Subspace == DefaultParamspace {
switch c.Key {
case string(types.KeyMaxDelegationsRatio):
err = afterChangedMaxDelegationsRatio(ctx, h.k)
}
}

return
}

// beforeChangedMaxValidators checks possibility for changing MaxValidators parameter
func beforeChangedMaxValidators(ctx sdk.Context, k Keeper, c params.ParamChange) error {
vc := len(k.GetAllValidators(ctx))
value, err := strconv.Atoi(c.Value)
if err != nil {
return errors.Wrap(err, "can not convert value to the int")
}

if vc < value {
return errors.Wrap(types.ErrDeniedChangingParam, "can not reduce validator quantity less than current amount")
}

return nil
}

// afterChangedMaxDelegationsRatio reduces delegations to the validator if delegations is overflow.
func afterChangedMaxDelegationsRatio(ctx sdk.Context, k Keeper) error {
for _, v := range k.GetAllValidators(ctx) {
selfStake, totalStake := k.GetValidatorStakingState(ctx, v.OperatorAddress).GetSelfAndTotalStakes(v)
if isOverflow, limit := k.HasValidatorDelegationsOverflow(ctx, selfStake, totalStake); isOverflow {
delegatedAmount := totalStake.Sub(selfStake)
needReduce := totalStake.Sub(limit)
reducedAmount := needReduce.ToDec()

delegators := k.GetValidatorDelegations(ctx, v.OperatorAddress)
for i, d := range delegators {
if d.DelegatorAddress.Equals(v.GetOperator()) {
continue
}

reducedShares := d.BondingShares.Mul(needReduce.ToDec()).Quo(delegatedAmount.ToDec())

if len(delegators) == i+1 {
reducedShares = reducedAmount
} else {
reducedAmount = reducedAmount.Sub(reducedShares)
}

_, err := k.Undelegate(ctx, d.DelegatorAddress, v.OperatorAddress, types.BondingDelOpType, reducedShares, true)
if err != nil {
return err
}
}
}
}

return nil
}
1 change: 1 addition & 0 deletions x/staking/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,5 @@ var (
ErrMaxDelegationsLimit = sdkerrors.Register(ModuleName, 47, "validator max delegations level reached")
ErrDeniedStakingOps = sdkerrors.Register(ModuleName, 48, "account cannot perform any staking operations (banned)")
ErrMaxSelfDelegationLimit = sdkerrors.Register(ModuleName, 49, "validator max self-delegation level reached")
ErrDeniedChangingParam = sdkerrors.Register(ModuleName, 50, "cannot change parameter")
)