2018-09-04 23:41:17 -07:00
|
|
|
package keeper
|
|
|
|
|
2018-09-11 10:35:47 -07:00
|
|
|
import (
|
2019-02-27 13:09:26 -08:00
|
|
|
"fmt"
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
|
|
|
2018-09-11 10:35:47 -07:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2019-06-26 09:03:25 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
2020-10-12 06:56:02 -07:00
|
|
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
2018-09-11 10:35:47 -07:00
|
|
|
)
|
2018-09-04 23:41:17 -07:00
|
|
|
|
2019-06-28 13:11:27 -07:00
|
|
|
// AllocateTokens handles distribution of the collected fees
|
2019-06-26 09:03:25 -07:00
|
|
|
func (k Keeper) AllocateTokens(
|
|
|
|
ctx sdk.Context, sumPreviousPrecommitPower, totalPreviousPower int64,
|
|
|
|
previousProposer sdk.ConsAddress, previousVotes []abci.VoteInfo,
|
|
|
|
) {
|
2019-03-14 11:13:15 -07:00
|
|
|
|
2019-04-15 20:58:06 -07:00
|
|
|
logger := k.Logger(ctx)
|
2018-10-22 20:55:49 -07:00
|
|
|
|
2019-03-14 11:13:15 -07:00
|
|
|
// fetch and clear the collected fees for distribution, since this is
|
|
|
|
// called in BeginBlock, collected fees will be from the previous block
|
|
|
|
// (and distributed to the previous proposer)
|
2020-04-20 12:32:10 -07:00
|
|
|
feeCollector := k.authKeeper.GetModuleAccount(ctx, k.feeCollectorName)
|
2020-01-30 13:31:16 -08:00
|
|
|
feesCollectedInt := k.bankKeeper.GetAllBalances(ctx, feeCollector.GetAddress())
|
2020-01-03 12:44:53 -08:00
|
|
|
feesCollected := sdk.NewDecCoinsFromCoins(feesCollectedInt...)
|
2019-06-28 13:11:27 -07:00
|
|
|
|
|
|
|
// transfer collected fees to the distribution module account
|
2020-04-20 08:22:12 -07:00
|
|
|
err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, k.feeCollectorName, types.ModuleName, feesCollectedInt)
|
2019-06-28 13:11:27 -07:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2018-09-11 10:35:47 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// temporary workaround to keep CanWithdrawInvariant happy
|
|
|
|
// general discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634
|
2019-03-14 11:13:15 -07:00
|
|
|
feePool := k.GetFeePool(ctx)
|
|
|
|
if totalPreviousPower == 0 {
|
2020-01-03 12:44:53 -08:00
|
|
|
feePool.CommunityPool = feePool.CommunityPool.Add(feesCollected...)
|
2018-11-27 00:14:22 -08:00
|
|
|
k.SetFeePool(ctx, feePool)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// calculate fraction votes
|
2019-03-14 11:13:15 -07:00
|
|
|
previousFractionVotes := sdk.NewDec(sumPreviousPrecommitPower).Quo(sdk.NewDec(totalPreviousPower))
|
2019-01-16 13:38:05 -08:00
|
|
|
|
2019-03-14 11:13:15 -07:00
|
|
|
// calculate previous proposer reward
|
2018-10-15 13:12:42 -07:00
|
|
|
baseProposerReward := k.GetBaseProposerReward(ctx)
|
|
|
|
bonusProposerReward := k.GetBonusProposerReward(ctx)
|
2019-03-14 11:13:15 -07:00
|
|
|
proposerMultiplier := baseProposerReward.Add(bonusProposerReward.MulTruncate(previousFractionVotes))
|
2019-02-26 10:23:11 -08:00
|
|
|
proposerReward := feesCollected.MulDecTruncate(proposerMultiplier)
|
2018-09-04 23:41:17 -07:00
|
|
|
|
2019-03-14 11:13:15 -07:00
|
|
|
// pay previous proposer
|
2019-02-27 13:09:26 -08:00
|
|
|
remaining := feesCollected
|
2019-03-14 11:13:15 -07:00
|
|
|
proposerValidator := k.stakingKeeper.ValidatorByConsAddr(ctx, previousProposer)
|
|
|
|
|
2019-02-27 13:09:26 -08:00
|
|
|
if proposerValidator != nil {
|
2019-06-26 09:03:25 -07:00
|
|
|
ctx.EventManager().EmitEvent(
|
|
|
|
sdk.NewEvent(
|
|
|
|
types.EventTypeProposerReward,
|
2019-07-24 15:50:34 -07:00
|
|
|
sdk.NewAttribute(sdk.AttributeKeyAmount, proposerReward.String()),
|
2019-06-26 09:03:25 -07:00
|
|
|
sdk.NewAttribute(types.AttributeKeyValidator, proposerValidator.GetOperator().String()),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2019-02-27 13:09:26 -08:00
|
|
|
k.AllocateTokensToValidator(ctx, proposerValidator, proposerReward)
|
2019-03-06 10:54:12 -08:00
|
|
|
remaining = remaining.Sub(proposerReward)
|
2019-02-27 13:09:26 -08:00
|
|
|
} else {
|
2019-03-14 11:13:15 -07:00
|
|
|
// previous proposer can be unknown if say, the unbonding period is 1 block, so
|
2019-02-27 13:09:26 -08:00
|
|
|
// e.g. a validator undelegates at block X, it's removed entirely by
|
|
|
|
// block X+1's endblock, then X+2 we need to refer to the previous
|
|
|
|
// proposer for X+1, but we've forgotten about them.
|
|
|
|
logger.Error(fmt.Sprintf(
|
2019-03-06 10:54:12 -08:00
|
|
|
"WARNING: Attempt to allocate proposer rewards to unknown proposer %s. "+
|
|
|
|
"This should happen only if the proposer unbonded completely within a single block, "+
|
|
|
|
"which generally should not happen except in exceptional circumstances (or fuzz testing). "+
|
|
|
|
"We recommend you investigate immediately.",
|
2019-03-14 11:13:15 -07:00
|
|
|
previousProposer.String()))
|
2019-02-27 13:09:26 -08:00
|
|
|
}
|
2018-09-04 23:41:17 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// calculate fraction allocated to validators
|
2018-09-18 21:42:05 -07:00
|
|
|
communityTax := k.GetCommunityTax(ctx)
|
2019-01-16 13:38:05 -08:00
|
|
|
voteMultiplier := sdk.OneDec().Sub(proposerMultiplier).Sub(communityTax)
|
2018-09-04 23:41:17 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// allocate tokens proportionally to voting power
|
|
|
|
// TODO consider parallelizing later, ref https://github.com/cosmos/cosmos-sdk/pull/3099#discussion_r246276376
|
2019-03-14 11:13:15 -07:00
|
|
|
for _, vote := range previousVotes {
|
2019-01-16 13:38:05 -08:00
|
|
|
validator := k.stakingKeeper.ValidatorByConsAddr(ctx, vote.Validator.Address)
|
2018-09-04 23:41:17 -07:00
|
|
|
|
2019-02-27 12:38:57 -08:00
|
|
|
// TODO consider microslashing for missing votes.
|
2019-01-16 13:38:05 -08:00
|
|
|
// ref https://github.com/cosmos/cosmos-sdk/issues/2525#issuecomment-430838701
|
2019-03-14 11:13:15 -07:00
|
|
|
powerFraction := sdk.NewDec(vote.Validator.Power).QuoTruncate(sdk.NewDec(totalPreviousPower))
|
2019-02-26 10:23:11 -08:00
|
|
|
reward := feesCollected.MulDecTruncate(voteMultiplier).MulDecTruncate(powerFraction)
|
2019-01-16 13:38:05 -08:00
|
|
|
k.AllocateTokensToValidator(ctx, validator, reward)
|
2019-02-21 09:35:55 -08:00
|
|
|
remaining = remaining.Sub(reward)
|
2019-01-16 13:38:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// allocate community funding
|
2020-01-03 12:44:53 -08:00
|
|
|
feePool.CommunityPool = feePool.CommunityPool.Add(remaining...)
|
2018-09-19 19:13:12 -07:00
|
|
|
k.SetFeePool(ctx, feePool)
|
2019-01-16 13:38:05 -08:00
|
|
|
}
|
|
|
|
|
2019-06-04 15:06:58 -07:00
|
|
|
// AllocateTokensToValidator allocate tokens to a particular validator, splitting according to commission
|
2020-10-12 06:56:02 -07:00
|
|
|
func (k Keeper) AllocateTokensToValidator(ctx sdk.Context, val stakingtypes.ValidatorI, tokens sdk.DecCoins) {
|
2019-01-16 13:38:05 -08:00
|
|
|
// split tokens between validator and delegators according to commission
|
|
|
|
commission := tokens.MulDec(val.GetCommission())
|
2019-02-21 09:35:55 -08:00
|
|
|
shared := tokens.Sub(commission)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// update current commission
|
2019-06-26 09:03:25 -07:00
|
|
|
ctx.EventManager().EmitEvent(
|
|
|
|
sdk.NewEvent(
|
|
|
|
types.EventTypeCommission,
|
2019-07-24 15:50:34 -07:00
|
|
|
sdk.NewAttribute(sdk.AttributeKeyAmount, commission.String()),
|
2019-06-26 09:03:25 -07:00
|
|
|
sdk.NewAttribute(types.AttributeKeyValidator, val.GetOperator().String()),
|
|
|
|
),
|
|
|
|
)
|
2019-01-16 13:38:05 -08:00
|
|
|
currentCommission := k.GetValidatorAccumulatedCommission(ctx, val.GetOperator())
|
2020-02-11 06:58:37 -08:00
|
|
|
currentCommission.Commission = currentCommission.Commission.Add(commission...)
|
2019-01-16 13:38:05 -08:00
|
|
|
k.SetValidatorAccumulatedCommission(ctx, val.GetOperator(), currentCommission)
|
|
|
|
|
|
|
|
// update current rewards
|
|
|
|
currentRewards := k.GetValidatorCurrentRewards(ctx, val.GetOperator())
|
2020-01-03 12:44:53 -08:00
|
|
|
currentRewards.Rewards = currentRewards.Rewards.Add(shared...)
|
2019-01-16 13:38:05 -08:00
|
|
|
k.SetValidatorCurrentRewards(ctx, val.GetOperator(), currentRewards)
|
2019-03-06 10:54:12 -08:00
|
|
|
|
|
|
|
// update outstanding rewards
|
2019-06-26 09:03:25 -07:00
|
|
|
ctx.EventManager().EmitEvent(
|
|
|
|
sdk.NewEvent(
|
|
|
|
types.EventTypeRewards,
|
2019-07-24 15:50:34 -07:00
|
|
|
sdk.NewAttribute(sdk.AttributeKeyAmount, tokens.String()),
|
2019-06-26 09:03:25 -07:00
|
|
|
sdk.NewAttribute(types.AttributeKeyValidator, val.GetOperator().String()),
|
|
|
|
),
|
|
|
|
)
|
2019-03-06 10:54:12 -08:00
|
|
|
outstanding := k.GetValidatorOutstandingRewards(ctx, val.GetOperator())
|
2020-02-11 06:58:37 -08:00
|
|
|
outstanding.Rewards = outstanding.Rewards.Add(tokens...)
|
2019-03-06 10:54:12 -08:00
|
|
|
k.SetValidatorOutstandingRewards(ctx, val.GetOperator(), outstanding)
|
2018-09-04 23:41:17 -07:00
|
|
|
}
|