github.com/cosmos/cosmos-sdk@v0.50.10/x/distribution/keeper/validator.go (about) 1 package keeper 2 3 import ( 4 "context" 5 "fmt" 6 7 "cosmossdk.io/math" 8 9 sdk "github.com/cosmos/cosmos-sdk/types" 10 "github.com/cosmos/cosmos-sdk/x/distribution/types" 11 stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" 12 ) 13 14 // initialize rewards for a new validator 15 func (k Keeper) initializeValidator(ctx context.Context, val stakingtypes.ValidatorI) error { 16 valBz, err := k.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator()) 17 if err != nil { 18 return err 19 } 20 // set initial historical rewards (period 0) with reference count of 1 21 err = k.SetValidatorHistoricalRewards(ctx, valBz, 0, types.NewValidatorHistoricalRewards(sdk.DecCoins{}, 1)) 22 if err != nil { 23 return err 24 } 25 26 // set current rewards (starting at period 1) 27 err = k.SetValidatorCurrentRewards(ctx, valBz, types.NewValidatorCurrentRewards(sdk.DecCoins{}, 1)) 28 if err != nil { 29 return err 30 } 31 32 // set accumulated commission 33 err = k.SetValidatorAccumulatedCommission(ctx, valBz, types.InitialValidatorAccumulatedCommission()) 34 if err != nil { 35 return err 36 } 37 38 // set outstanding rewards 39 err = k.SetValidatorOutstandingRewards(ctx, valBz, types.ValidatorOutstandingRewards{Rewards: sdk.DecCoins{}}) 40 return err 41 } 42 43 // increment validator period, returning the period just ended 44 func (k Keeper) IncrementValidatorPeriod(ctx context.Context, val stakingtypes.ValidatorI) (uint64, error) { 45 valBz, err := k.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator()) 46 if err != nil { 47 return 0, err 48 } 49 50 // fetch current rewards 51 rewards, err := k.GetValidatorCurrentRewards(ctx, valBz) 52 if err != nil { 53 return 0, err 54 } 55 56 // calculate current ratio 57 var current sdk.DecCoins 58 if val.GetTokens().IsZero() { 59 60 // can't calculate ratio for zero-token validators 61 // ergo we instead add to the community pool 62 feePool, err := k.FeePool.Get(ctx) 63 if err != nil { 64 return 0, err 65 } 66 67 outstanding, err := k.GetValidatorOutstandingRewards(ctx, valBz) 68 if err != nil { 69 return 0, err 70 } 71 72 feePool.CommunityPool = feePool.CommunityPool.Add(rewards.Rewards...) 73 outstanding.Rewards = outstanding.GetRewards().Sub(rewards.Rewards) 74 err = k.FeePool.Set(ctx, feePool) 75 if err != nil { 76 return 0, err 77 } 78 79 err = k.SetValidatorOutstandingRewards(ctx, valBz, outstanding) 80 if err != nil { 81 return 0, err 82 } 83 84 current = sdk.DecCoins{} 85 } else { 86 // note: necessary to truncate so we don't allow withdrawing more rewards than owed 87 current = rewards.Rewards.QuoDecTruncate(math.LegacyNewDecFromInt(val.GetTokens())) 88 } 89 90 // fetch historical rewards for last period 91 historical, err := k.GetValidatorHistoricalRewards(ctx, valBz, rewards.Period-1) 92 if err != nil { 93 return 0, err 94 } 95 96 cumRewardRatio := historical.CumulativeRewardRatio 97 98 // decrement reference count 99 err = k.decrementReferenceCount(ctx, valBz, rewards.Period-1) 100 if err != nil { 101 return 0, err 102 } 103 104 // set new historical rewards with reference count of 1 105 err = k.SetValidatorHistoricalRewards(ctx, valBz, rewards.Period, types.NewValidatorHistoricalRewards(cumRewardRatio.Add(current...), 1)) 106 if err != nil { 107 return 0, err 108 } 109 110 // set current rewards, incrementing period by 1 111 err = k.SetValidatorCurrentRewards(ctx, valBz, types.NewValidatorCurrentRewards(sdk.DecCoins{}, rewards.Period+1)) 112 if err != nil { 113 return 0, err 114 } 115 116 return rewards.Period, nil 117 } 118 119 // increment the reference count for a historical rewards value 120 func (k Keeper) incrementReferenceCount(ctx context.Context, valAddr sdk.ValAddress, period uint64) error { 121 historical, err := k.GetValidatorHistoricalRewards(ctx, valAddr, period) 122 if err != nil { 123 return err 124 } 125 if historical.ReferenceCount > 2 { 126 panic("reference count should never exceed 2") 127 } 128 historical.ReferenceCount++ 129 return k.SetValidatorHistoricalRewards(ctx, valAddr, period, historical) 130 } 131 132 // decrement the reference count for a historical rewards value, and delete if zero references remain 133 func (k Keeper) decrementReferenceCount(ctx context.Context, valAddr sdk.ValAddress, period uint64) error { 134 historical, err := k.GetValidatorHistoricalRewards(ctx, valAddr, period) 135 if err != nil { 136 return err 137 } 138 139 if historical.ReferenceCount == 0 { 140 panic("cannot set negative reference count") 141 } 142 historical.ReferenceCount-- 143 if historical.ReferenceCount == 0 { 144 return k.DeleteValidatorHistoricalReward(ctx, valAddr, period) 145 } 146 147 return k.SetValidatorHistoricalRewards(ctx, valAddr, period, historical) 148 } 149 150 func (k Keeper) updateValidatorSlashFraction(ctx context.Context, valAddr sdk.ValAddress, fraction math.LegacyDec) error { 151 if fraction.GT(math.LegacyOneDec()) || fraction.IsNegative() { 152 panic(fmt.Sprintf("fraction must be >=0 and <=1, current fraction: %v", fraction)) 153 } 154 155 sdkCtx := sdk.UnwrapSDKContext(ctx) 156 val, err := k.stakingKeeper.Validator(ctx, valAddr) 157 if err != nil { 158 return err 159 } 160 161 // increment current period 162 newPeriod, err := k.IncrementValidatorPeriod(ctx, val) 163 if err != nil { 164 return err 165 } 166 167 // increment reference count on period we need to track 168 k.incrementReferenceCount(ctx, valAddr, newPeriod) 169 170 slashEvent := types.NewValidatorSlashEvent(newPeriod, fraction) 171 height := uint64(sdkCtx.BlockHeight()) 172 173 return k.SetValidatorSlashEvent(ctx, valAddr, height, newPeriod, slashEvent) 174 }