diff --git a/PENDING.md b/PENDING.md index 7db3b567db4f..5d6a7e82d761 100644 --- a/PENDING.md +++ b/PENDING.md @@ -43,7 +43,9 @@ IMPROVEMENTS * Gaia * SDK - - \#1277 Complete bank module specification + * \#1277 Complete bank module specification + * \#2914 No longer withdraw validator rewards on bond/unbond, but rather move + the rewards to the respective validator's pools. * Tendermint diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index f1fe47c09843..270fe52ec96e 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -138,10 +138,11 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio ) // register the staking hooks - // NOTE: stakeKeeper above are passed by reference, - // so that it can be modified like below: + // NOTE: The stakeKeeper above is passed by reference, so that it can be + // modified like below: app.stakeKeeper = *stakeKeeper.SetHooks( - NewHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks())) + NewStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()), + ) // register message routes app.Router(). @@ -318,52 +319,53 @@ func (app *GaiaApp) LoadHeight(height int64) error { //______________________________________________________________________________________________ -// Combined Staking Hooks -type Hooks struct { +var _ sdk.StakingHooks = StakingHooks{} + +// StakingHooks contains combined distribution and slashing hooks needed for the +// staking module. +type StakingHooks struct { dh distr.Hooks sh slashing.Hooks } -func NewHooks(dh distr.Hooks, sh slashing.Hooks) Hooks { - return Hooks{dh, sh} +func NewStakingHooks(dh distr.Hooks, sh slashing.Hooks) StakingHooks { + return StakingHooks{dh, sh} } -var _ sdk.StakingHooks = Hooks{} - // nolint -func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { +func (h StakingHooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { h.dh.OnValidatorCreated(ctx, valAddr) h.sh.OnValidatorCreated(ctx, valAddr) } -func (h Hooks) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) { +func (h StakingHooks) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) { h.dh.OnValidatorModified(ctx, valAddr) h.sh.OnValidatorModified(ctx, valAddr) } -func (h Hooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { +func (h StakingHooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { h.dh.OnValidatorRemoved(ctx, consAddr, valAddr) h.sh.OnValidatorRemoved(ctx, consAddr, valAddr) } -func (h Hooks) OnValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { +func (h StakingHooks) OnValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { h.dh.OnValidatorBonded(ctx, consAddr, valAddr) h.sh.OnValidatorBonded(ctx, consAddr, valAddr) } -func (h Hooks) OnValidatorPowerDidChange(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { +func (h StakingHooks) OnValidatorPowerDidChange(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { h.dh.OnValidatorPowerDidChange(ctx, consAddr, valAddr) h.sh.OnValidatorPowerDidChange(ctx, consAddr, valAddr) } -func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { +func (h StakingHooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { h.dh.OnValidatorBeginUnbonding(ctx, consAddr, valAddr) h.sh.OnValidatorBeginUnbonding(ctx, consAddr, valAddr) } -func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { +func (h StakingHooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { h.dh.OnDelegationCreated(ctx, delAddr, valAddr) h.sh.OnDelegationCreated(ctx, delAddr, valAddr) } -func (h Hooks) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { +func (h StakingHooks) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { h.dh.OnDelegationSharesModified(ctx, delAddr, valAddr) h.sh.OnDelegationSharesModified(ctx, delAddr, valAddr) } -func (h Hooks) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { +func (h StakingHooks) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { h.dh.OnDelegationRemoved(ctx, delAddr, valAddr) h.sh.OnDelegationRemoved(ctx, delAddr, valAddr) } diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go index 728dfb269f37..dc54a6e4fe5f 100644 --- a/x/distribution/keeper/delegation.go +++ b/x/distribution/keeper/delegation.go @@ -161,12 +161,12 @@ func (k Keeper) WithdrawDelegationReward(ctx sdk.Context, delAddr sdk.AccAddress return types.ErrNoDelegationDistInfo(k.codespace) } - feePool, valInfo, delInfo, withdraw := - k.withdrawDelegationReward(ctx, delAddr, valAddr) + feePool, valInfo, delInfo, withdraw := k.withdrawDelegationReward(ctx, delAddr, valAddr) k.SetValidatorDistInfo(ctx, valInfo) k.SetDelegationDistInfo(ctx, delInfo) k.WithdrawToDelegator(ctx, feePool, delAddr, withdraw) + return nil } @@ -194,19 +194,21 @@ func (k Keeper) WithdrawDelegationRewardsAll(ctx sdk.Context, delAddr sdk.AccAdd func (k Keeper) withdrawDelegationRewardsAll(ctx sdk.Context, delAddr sdk.AccAddress) types.DecCoins { - // iterate over all the delegations withdraw := types.DecCoins{} - operationAtDelegation := func(_ int64, del sdk.Delegation) (stop bool) { + // iterate over all the delegations + operationAtDelegation := func(_ int64, del sdk.Delegation) (stop bool) { valAddr := del.GetValidatorAddr() - feePool, valInfo, delInfo, diWithdraw := - k.withdrawDelegationReward(ctx, delAddr, valAddr) + feePool, valInfo, delInfo, diWithdraw := k.withdrawDelegationReward(ctx, delAddr, valAddr) withdraw = withdraw.Plus(diWithdraw) + k.SetFeePool(ctx, feePool) k.SetValidatorDistInfo(ctx, valInfo) k.SetDelegationDistInfo(ctx, delInfo) + return false } + k.stakeKeeper.IterateDelegations(ctx, delAddr, operationAtDelegation) return withdraw } diff --git a/x/distribution/keeper/hooks.go b/x/distribution/keeper/hooks.go index b531a40429a9..260ee2e77cdb 100644 --- a/x/distribution/keeper/hooks.go +++ b/x/distribution/keeper/hooks.go @@ -28,9 +28,11 @@ func (k Keeper) onValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { // Withdraw all validator rewards func (k Keeper) onValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) { - // This doesn't need to be run at genesis + // Move the validator's rewards from the global pool to the validator's pools + // (dist info), but without actually withdrawing the rewards. This does not + // need to happen during the genesis block. if ctx.BlockHeight() > 0 { - if err := k.WithdrawValidatorRewardsAll(ctx, valAddr); err != nil { + if err := k.updateValidatorDistInfoFromPool(ctx, valAddr); err != nil { panic(err) } } diff --git a/x/distribution/keeper/validator.go b/x/distribution/keeper/validator.go index 97eb5bc50eb3..951ba280a584 100644 --- a/x/distribution/keeper/validator.go +++ b/x/distribution/keeper/validator.go @@ -91,6 +91,24 @@ func (k Keeper) GetValidatorAccum(ctx sdk.Context, operatorAddr sdk.ValAddress) return accum, nil } +// updateValidatorDistInfoFromPool updates the validator's distribution info +// from the global fee pool without withdrawing any rewards. This will be called +// from a onValidatorModified hook. +func (k Keeper) updateValidatorDistInfoFromPool(ctx sdk.Context, operatorAddr sdk.ValAddress) sdk.Error { + if !k.HasValidatorDistInfo(ctx, operatorAddr) { + return types.ErrNoValidatorDistInfo(k.codespace) + } + + valInfo := k.GetValidatorDistInfo(ctx, operatorAddr) + wc := k.GetWithdrawContext(ctx, operatorAddr) + valInfo, feePool := valInfo.TakeFeePoolRewards(wc) + + k.SetFeePool(ctx, feePool) + k.SetValidatorDistInfo(ctx, valInfo) + + return nil +} + // withdrawal all the validator rewards including the commission func (k Keeper) WithdrawValidatorRewardsAll(ctx sdk.Context, operatorAddr sdk.ValAddress) sdk.Error { diff --git a/x/stake/keeper/hooks.go b/x/stake/keeper/hooks.go index 74e830490647..4ae158786eec 100644 --- a/x/stake/keeper/hooks.go +++ b/x/stake/keeper/hooks.go @@ -11,6 +11,7 @@ func (k Keeper) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { k.hooks.OnValidatorCreated(ctx, valAddr) } } + func (k Keeper) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) { if k.hooks != nil { k.hooks.OnValidatorModified(ctx, valAddr)