github.com/cosmos/cosmos-sdk@v0.50.10/x/distribution/keeper/delegation_test.go (about) 1 package keeper_test 2 3 import ( 4 "testing" 5 6 cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" 7 "github.com/golang/mock/gomock" 8 "github.com/stretchr/testify/require" 9 10 "cosmossdk.io/math" 11 storetypes "cosmossdk.io/store/types" 12 13 "github.com/cosmos/cosmos-sdk/codec/address" 14 "github.com/cosmos/cosmos-sdk/runtime" 15 "github.com/cosmos/cosmos-sdk/testutil" 16 sdk "github.com/cosmos/cosmos-sdk/types" 17 moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" 18 authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 19 "github.com/cosmos/cosmos-sdk/x/distribution" 20 "github.com/cosmos/cosmos-sdk/x/distribution/keeper" 21 distrtestutil "github.com/cosmos/cosmos-sdk/x/distribution/testutil" 22 disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" 23 stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" 24 ) 25 26 func TestCalculateRewardsBasic(t *testing.T) { 27 ctrl := gomock.NewController(t) 28 key := storetypes.NewKVStoreKey(disttypes.StoreKey) 29 storeService := runtime.NewKVStoreService(key) 30 testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test")) 31 encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) 32 ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Height: 1}) 33 34 bankKeeper := distrtestutil.NewMockBankKeeper(ctrl) 35 stakingKeeper := distrtestutil.NewMockStakingKeeper(ctrl) 36 accountKeeper := distrtestutil.NewMockAccountKeeper(ctrl) 37 38 accountKeeper.EXPECT().GetModuleAddress("distribution").Return(distrAcc.GetAddress()) 39 stakingKeeper.EXPECT().ValidatorAddressCodec().Return(address.NewBech32Codec(sdk.Bech32PrefixValAddr)).AnyTimes() 40 accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec(sdk.Bech32MainPrefix)).AnyTimes() 41 42 distrKeeper := keeper.NewKeeper( 43 encCfg.Codec, 44 storeService, 45 accountKeeper, 46 bankKeeper, 47 stakingKeeper, 48 "fee_collector", 49 authtypes.NewModuleAddress("gov").String(), 50 ) 51 52 // reset fee pool 53 require.NoError(t, distrKeeper.FeePool.Set(ctx, disttypes.InitialFeePool())) 54 require.NoError(t, distrKeeper.Params.Set(ctx, disttypes.DefaultParams())) 55 56 // create validator with 50% commission 57 valAddr := sdk.ValAddress(valConsAddr0) 58 addr := sdk.AccAddress(valAddr) 59 val, err := distrtestutil.CreateValidator(valConsPk0, math.NewInt(1000)) 60 require.NoError(t, err) 61 val.Commission = stakingtypes.NewCommission(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)) 62 63 // delegation mock 64 del := stakingtypes.NewDelegation(addr.String(), valAddr.String(), val.DelegatorShares) 65 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(3) 66 stakingKeeper.EXPECT().Delegation(gomock.Any(), addr, valAddr).Return(del, nil) 67 68 // run the necessary hooks manually (given that we are not running an actual staking module) 69 err = distrtestutil.CallCreateValidatorHooks(ctx, distrKeeper, addr, valAddr) 70 require.NoError(t, err) 71 72 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 73 74 // historical count should be 2 (once for validator init, once for delegation init) 75 require.Equal(t, uint64(2), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) 76 77 // end period 78 endingPeriod, _ := distrKeeper.IncrementValidatorPeriod(ctx, val) 79 80 // historical count should be 2 still 81 require.Equal(t, uint64(2), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) 82 83 // calculate delegation rewards 84 rewards, err := distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 85 require.NoError(t, err) 86 87 // rewards should be zero 88 require.True(t, rewards.IsZero()) 89 90 // allocate some rewards 91 initial := int64(10) 92 tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial)}} 93 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 94 95 // end period 96 endingPeriod, _ = distrKeeper.IncrementValidatorPeriod(ctx, val) 97 98 // calculate delegation rewards 99 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 100 require.NoError(t, err) 101 102 // rewards should be half the tokens 103 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 2)}}, rewards) 104 105 // commission should be the other half 106 valCommission, err := distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddr) 107 require.NoError(t, err) 108 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 2)}}, valCommission.Commission) 109 } 110 111 func TestCalculateRewardsAfterSlash(t *testing.T) { 112 ctrl := gomock.NewController(t) 113 key := storetypes.NewKVStoreKey(disttypes.StoreKey) 114 storeService := runtime.NewKVStoreService(key) 115 testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test")) 116 encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) 117 ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Height: 1}) 118 119 bankKeeper := distrtestutil.NewMockBankKeeper(ctrl) 120 stakingKeeper := distrtestutil.NewMockStakingKeeper(ctrl) 121 accountKeeper := distrtestutil.NewMockAccountKeeper(ctrl) 122 123 accountKeeper.EXPECT().GetModuleAddress("distribution").Return(distrAcc.GetAddress()) 124 stakingKeeper.EXPECT().ValidatorAddressCodec().Return(address.NewBech32Codec(sdk.Bech32PrefixValAddr)).AnyTimes() 125 accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec(sdk.Bech32MainPrefix)).AnyTimes() 126 127 distrKeeper := keeper.NewKeeper( 128 encCfg.Codec, 129 storeService, 130 accountKeeper, 131 bankKeeper, 132 stakingKeeper, 133 "fee_collector", 134 authtypes.NewModuleAddress("gov").String(), 135 ) 136 137 // reset fee pool 138 require.NoError(t, distrKeeper.FeePool.Set(ctx, disttypes.InitialFeePool())) 139 require.NoError(t, distrKeeper.Params.Set(ctx, disttypes.DefaultParams())) 140 141 // create validator with 50% commission 142 valAddr := sdk.ValAddress(valConsAddr0) 143 addr := sdk.AccAddress(valAddr) 144 valPower := int64(100) 145 stake := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction) 146 val, err := distrtestutil.CreateValidator(valConsPk0, stake) 147 require.NoError(t, err) 148 val.Commission = stakingtypes.NewCommission(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)) 149 150 del := stakingtypes.NewDelegation(addr.String(), valAddr.String(), val.DelegatorShares) 151 152 // set mock calls 153 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(4) 154 stakingKeeper.EXPECT().Delegation(gomock.Any(), addr, valAddr).Return(del, nil) 155 156 // run the necessary hooks manually (given that we are not running an actual staking module) 157 err = distrtestutil.CallCreateValidatorHooks(ctx, distrKeeper, addr, valAddr) 158 require.NoError(t, err) 159 160 // next block 161 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 162 163 // end period 164 endingPeriod, _ := distrKeeper.IncrementValidatorPeriod(ctx, val) 165 166 // calculate delegation rewards 167 rewards, err := distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 168 require.NoError(t, err) 169 170 // rewards should be zero 171 require.True(t, rewards.IsZero()) 172 173 // start out block height 174 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 175 176 // slash the validator by 50% (simulated with manual calls; we assume the validator is bonded) 177 slashedTokens := distrtestutil.SlashValidator( 178 ctx, 179 valConsAddr0, 180 ctx.BlockHeight(), 181 valPower, 182 math.LegacyNewDecWithPrec(5, 1), 183 &val, 184 &distrKeeper, 185 stakingKeeper, 186 ) 187 require.True(t, slashedTokens.IsPositive(), "expected positive slashed tokens, got: %s", slashedTokens) 188 189 // increase block height 190 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 191 192 // allocate some rewards 193 initial := sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction) 194 tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDecFromInt(initial)}} 195 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 196 197 // end period 198 endingPeriod, _ = distrKeeper.IncrementValidatorPeriod(ctx, val) 199 200 // calculate delegation rewards 201 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 202 require.NoError(t, err) 203 204 // rewards should be half the tokens 205 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDecFromInt(initial.QuoRaw(2))}}, rewards) 206 207 // commission should be the other half 208 valCommission, err := distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddr) 209 require.NoError(t, err) 210 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDecFromInt(initial.QuoRaw(2))}}, 211 valCommission.Commission) 212 } 213 214 func TestCalculateRewardsAfterManySlashes(t *testing.T) { 215 ctrl := gomock.NewController(t) 216 key := storetypes.NewKVStoreKey(disttypes.StoreKey) 217 storeService := runtime.NewKVStoreService(key) 218 testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test")) 219 encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) 220 ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Height: 1}) 221 222 bankKeeper := distrtestutil.NewMockBankKeeper(ctrl) 223 stakingKeeper := distrtestutil.NewMockStakingKeeper(ctrl) 224 accountKeeper := distrtestutil.NewMockAccountKeeper(ctrl) 225 226 accountKeeper.EXPECT().GetModuleAddress("distribution").Return(distrAcc.GetAddress()) 227 stakingKeeper.EXPECT().ValidatorAddressCodec().Return(address.NewBech32Codec(sdk.Bech32PrefixValAddr)).AnyTimes() 228 accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec(sdk.Bech32MainPrefix)).AnyTimes() 229 230 distrKeeper := keeper.NewKeeper( 231 encCfg.Codec, 232 storeService, 233 accountKeeper, 234 bankKeeper, 235 stakingKeeper, 236 "fee_collector", 237 authtypes.NewModuleAddress("gov").String(), 238 ) 239 240 // reset fee pool 241 require.NoError(t, distrKeeper.FeePool.Set(ctx, disttypes.InitialFeePool())) 242 require.NoError(t, distrKeeper.Params.Set(ctx, disttypes.DefaultParams())) 243 244 // create validator with 50% commission 245 valAddr := sdk.ValAddress(valConsAddr0) 246 addr := sdk.AccAddress(valAddr) 247 valPower := int64(100) 248 stake := sdk.TokensFromConsensusPower(valPower, sdk.DefaultPowerReduction) 249 val, err := distrtestutil.CreateValidator(valConsPk0, stake) 250 require.NoError(t, err) 251 val.Commission = stakingtypes.NewCommission(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)) 252 253 // delegation mocks 254 del := stakingtypes.NewDelegation(addr.String(), valAddr.String(), val.DelegatorShares) 255 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(4) 256 stakingKeeper.EXPECT().Delegation(gomock.Any(), addr, valAddr).Return(del, nil) 257 258 // run the necessary hooks manually (given that we are not running an actual staking module) 259 err = distrtestutil.CallCreateValidatorHooks(ctx, distrKeeper, addr, valAddr) 260 require.NoError(t, err) 261 262 // next block 263 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 264 265 // end period 266 endingPeriod, _ := distrKeeper.IncrementValidatorPeriod(ctx, val) 267 268 // calculate delegation rewards 269 rewards, err := distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 270 require.NoError(t, err) 271 272 // rewards should be zero 273 require.True(t, rewards.IsZero()) 274 275 // start out block height 276 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 277 278 // slash the validator by 50% (simulated with manual calls; we assume the validator is bonded) 279 slashedTokens := distrtestutil.SlashValidator( 280 ctx, 281 valConsAddr0, 282 ctx.BlockHeight(), 283 valPower, 284 math.LegacyNewDecWithPrec(5, 1), 285 &val, 286 &distrKeeper, 287 stakingKeeper, 288 ) 289 require.True(t, slashedTokens.IsPositive(), "expected positive slashed tokens, got: %s", slashedTokens) 290 291 // expect a call for the next slash with the updated validator 292 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(1) 293 294 // increase block height 295 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 296 297 // allocate some rewards 298 initial := sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction) 299 tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDecFromInt(initial)}} 300 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 301 302 // slash the validator by 50% again 303 slashedTokens = distrtestutil.SlashValidator( 304 ctx, 305 valConsAddr0, 306 ctx.BlockHeight(), 307 valPower/2, 308 math.LegacyNewDecWithPrec(2, 1), 309 &val, 310 &distrKeeper, 311 stakingKeeper, 312 ) 313 require.True(t, slashedTokens.IsPositive(), "expected positive slashed tokens, got: %s", slashedTokens) 314 315 // increase block height 316 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 317 318 // allocate some more rewards 319 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 320 321 // end period 322 endingPeriod, _ = distrKeeper.IncrementValidatorPeriod(ctx, val) 323 324 // calculate delegation rewards 325 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 326 require.NoError(t, err) 327 328 // rewards should be half the tokens 329 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDecFromInt(initial)}}, rewards) 330 331 // commission should be the other half 332 valCommission, err := distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddr) 333 require.NoError(t, err) 334 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDecFromInt(initial)}}, 335 valCommission.Commission) 336 } 337 338 func TestCalculateRewardsMultiDelegator(t *testing.T) { 339 ctrl := gomock.NewController(t) 340 key := storetypes.NewKVStoreKey(disttypes.StoreKey) 341 storeService := runtime.NewKVStoreService(key) 342 testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test")) 343 encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) 344 ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Height: 1}) 345 346 bankKeeper := distrtestutil.NewMockBankKeeper(ctrl) 347 stakingKeeper := distrtestutil.NewMockStakingKeeper(ctrl) 348 accountKeeper := distrtestutil.NewMockAccountKeeper(ctrl) 349 350 accountKeeper.EXPECT().GetModuleAddress("distribution").Return(distrAcc.GetAddress()) 351 stakingKeeper.EXPECT().ValidatorAddressCodec().Return(address.NewBech32Codec(sdk.Bech32PrefixValAddr)).AnyTimes() 352 accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec(sdk.Bech32MainPrefix)).AnyTimes() 353 354 distrKeeper := keeper.NewKeeper( 355 encCfg.Codec, 356 storeService, 357 accountKeeper, 358 bankKeeper, 359 stakingKeeper, 360 "fee_collector", 361 authtypes.NewModuleAddress("gov").String(), 362 ) 363 364 // reset fee pool 365 require.NoError(t, distrKeeper.FeePool.Set(ctx, disttypes.InitialFeePool())) 366 require.NoError(t, distrKeeper.Params.Set(ctx, disttypes.DefaultParams())) 367 368 // create validator with 50% commission 369 valAddr := sdk.ValAddress(valConsAddr0) 370 addr0 := sdk.AccAddress(valAddr) 371 val, err := distrtestutil.CreateValidator(valConsPk0, math.NewInt(100)) 372 require.NoError(t, err) 373 374 val.Commission = stakingtypes.NewCommission(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)) 375 376 del0 := stakingtypes.NewDelegation(addr0.String(), valAddr.String(), val.DelegatorShares) 377 378 // set mock calls 379 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(4) 380 stakingKeeper.EXPECT().Delegation(gomock.Any(), addr0, valAddr).Return(del0, nil).Times(1) 381 382 // run the necessary hooks manually (given that we are not running an actual staking module) 383 err = distrtestutil.CallCreateValidatorHooks(ctx, distrKeeper, addr0, valAddr) 384 require.NoError(t, err) 385 386 // next block 387 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 388 389 // allocate some rewards 390 initial := int64(20) 391 tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial)}} 392 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 393 394 // second delegation 395 addr1 := sdk.AccAddress(valConsAddr1) 396 _, del1, err := distrtestutil.Delegate(ctx, distrKeeper, addr1, &val, math.NewInt(100), nil, stakingKeeper) 397 require.NoError(t, err) 398 399 stakingKeeper.EXPECT().Delegation(gomock.Any(), addr1, valAddr).Return(del1, nil) 400 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(1) 401 402 // call necessary hooks to update a delegation 403 err = distrKeeper.Hooks().AfterDelegationModified(ctx, addr1, valAddr) 404 require.NoError(t, err) 405 406 // next block 407 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 408 409 // allocate some more rewards 410 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 411 412 // end period 413 endingPeriod, _ := distrKeeper.IncrementValidatorPeriod(ctx, val) 414 415 // calculate delegation rewards for del1 416 rewards, err := distrKeeper.CalculateDelegationRewards(ctx, val, del0, endingPeriod) 417 require.NoError(t, err) 418 419 // rewards for del0 should be 3/4 initial 420 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial * 3 / 4)}}, rewards) 421 422 // calculate delegation rewards for del2 423 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) 424 require.NoError(t, err) 425 426 // rewards for del2 should be 1/4 initial 427 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial * 1 / 4)}}, rewards) 428 429 // commission should be equal to initial (50% twice) 430 valCommission, err := distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddr) 431 require.NoError(t, err) 432 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial)}}, valCommission.Commission) 433 } 434 435 func TestWithdrawDelegationRewardsBasic(t *testing.T) { 436 ctrl := gomock.NewController(t) 437 key := storetypes.NewKVStoreKey(disttypes.StoreKey) 438 storeService := runtime.NewKVStoreService(key) 439 testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test")) 440 encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) 441 ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Height: 1}) 442 443 bankKeeper := distrtestutil.NewMockBankKeeper(ctrl) 444 stakingKeeper := distrtestutil.NewMockStakingKeeper(ctrl) 445 accountKeeper := distrtestutil.NewMockAccountKeeper(ctrl) 446 447 accountKeeper.EXPECT().GetModuleAddress("distribution").Return(distrAcc.GetAddress()) 448 stakingKeeper.EXPECT().ValidatorAddressCodec().Return(address.NewBech32Codec(sdk.Bech32PrefixValAddr)).AnyTimes() 449 accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec(sdk.Bech32MainPrefix)).AnyTimes() 450 451 distrKeeper := keeper.NewKeeper( 452 encCfg.Codec, 453 storeService, 454 accountKeeper, 455 bankKeeper, 456 stakingKeeper, 457 "fee_collector", 458 authtypes.NewModuleAddress("gov").String(), 459 ) 460 461 // reset fee pool 462 require.NoError(t, distrKeeper.FeePool.Set(ctx, disttypes.InitialFeePool())) 463 require.NoError(t, distrKeeper.Params.Set(ctx, disttypes.DefaultParams())) 464 465 // create validator with 50% commission 466 valAddr := sdk.ValAddress(valConsAddr0) 467 addr := sdk.AccAddress(valAddr) 468 val, err := distrtestutil.CreateValidator(valConsPk0, math.NewInt(100)) 469 require.NoError(t, err) 470 471 val.Commission = stakingtypes.NewCommission(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)) 472 473 // delegation mock 474 del := stakingtypes.NewDelegation(addr.String(), valAddr.String(), val.DelegatorShares) 475 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(5) 476 stakingKeeper.EXPECT().Delegation(gomock.Any(), addr, valAddr).Return(del, nil).Times(3) 477 478 // run the necessary hooks manually (given that we are not running an actual staking module) 479 err = distrtestutil.CallCreateValidatorHooks(ctx, distrKeeper, addr, valAddr) 480 require.NoError(t, err) 481 482 // next block 483 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 484 485 // allocate some rewards 486 initial := sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction) 487 tokens := sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, initial)} 488 489 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 490 491 // historical count should be 2 (initial + latest for delegation) 492 require.Equal(t, uint64(2), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) 493 494 // withdraw rewards (the bank keeper should be called with the right amount of tokens to transfer) 495 expRewards := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, initial.QuoRaw(2))} 496 bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, disttypes.ModuleName, addr, expRewards) 497 _, err = distrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddr), valAddr) 498 require.Nil(t, err) 499 500 // historical count should still be 2 (added one record, cleared one) 501 require.Equal(t, uint64(2), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) 502 503 // withdraw commission (the bank keeper should be called with the right amount of tokens to transfer) 504 expCommission := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, initial.QuoRaw(2))} 505 bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, disttypes.ModuleName, addr, expCommission) 506 _, err = distrKeeper.WithdrawValidatorCommission(ctx, valAddr) 507 require.Nil(t, err) 508 } 509 510 func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { 511 ctrl := gomock.NewController(t) 512 key := storetypes.NewKVStoreKey(disttypes.StoreKey) 513 storeService := runtime.NewKVStoreService(key) 514 testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test")) 515 encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) 516 ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Height: 1}) 517 518 bankKeeper := distrtestutil.NewMockBankKeeper(ctrl) 519 stakingKeeper := distrtestutil.NewMockStakingKeeper(ctrl) 520 accountKeeper := distrtestutil.NewMockAccountKeeper(ctrl) 521 522 accountKeeper.EXPECT().GetModuleAddress("distribution").Return(distrAcc.GetAddress()) 523 stakingKeeper.EXPECT().ValidatorAddressCodec().Return(address.NewBech32Codec(sdk.Bech32PrefixValAddr)).AnyTimes() 524 accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec(sdk.Bech32MainPrefix)).AnyTimes() 525 526 distrKeeper := keeper.NewKeeper( 527 encCfg.Codec, 528 storeService, 529 accountKeeper, 530 bankKeeper, 531 stakingKeeper, 532 "fee_collector", 533 authtypes.NewModuleAddress("gov").String(), 534 ) 535 536 // reset fee pool 537 require.NoError(t, distrKeeper.FeePool.Set(ctx, disttypes.InitialFeePool())) 538 require.NoError(t, distrKeeper.Params.Set(ctx, disttypes.DefaultParams())) 539 540 // create validator with 50% commission 541 valAddr := sdk.ValAddress(valConsAddr0) 542 addr := sdk.AccAddress(valAddr) 543 val, err := distrtestutil.CreateValidator(valConsPk0, math.NewInt(100)) 544 require.NoError(t, err) 545 546 val.Commission = stakingtypes.NewCommission(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)) 547 548 // delegation mock 549 del := stakingtypes.NewDelegation(addr.String(), valAddr.String(), val.DelegatorShares) 550 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(5) 551 stakingKeeper.EXPECT().Delegation(gomock.Any(), addr, valAddr).Return(del, nil) 552 553 // run the necessary hooks manually (given that we are not running an actual staking module) 554 err = distrtestutil.CallCreateValidatorHooks(ctx, distrKeeper, addr, valAddr) 555 require.NoError(t, err) 556 557 // next block 558 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 559 560 // end period 561 endingPeriod, _ := distrKeeper.IncrementValidatorPeriod(ctx, val) 562 563 // calculate delegation rewards 564 rewards, err := distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 565 require.NoError(t, err) 566 567 // rewards should be zero 568 require.True(t, rewards.IsZero()) 569 570 // start out block height 571 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 572 573 // allocate some rewards 574 initial := math.LegacyNewDecFromInt(sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction)) 575 tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}} 576 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 577 578 valPower := int64(100) 579 // slash the validator by 50% (simulated with manual calls; we assume the validator is bonded) 580 distrtestutil.SlashValidator( 581 ctx, 582 valConsAddr0, 583 ctx.BlockHeight(), 584 valPower, 585 math.LegacyNewDecWithPrec(5, 1), 586 &val, 587 &distrKeeper, 588 stakingKeeper, 589 ) 590 591 // slash the validator by 50% again 592 // stakingKeeper.Slash(ctx, valConsAddr0, ctx.BlockHeight(), valPower/2, math.LegacyNewDecWithPrec(5, 1)) 593 distrtestutil.SlashValidator( 594 ctx, 595 valConsAddr0, 596 ctx.BlockHeight(), 597 valPower/2, 598 math.LegacyNewDecWithPrec(5, 1), 599 &val, 600 &distrKeeper, 601 stakingKeeper, 602 ) 603 604 // increase block height 605 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 606 607 // allocate some more rewards 608 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 609 610 // end period 611 endingPeriod, _ = distrKeeper.IncrementValidatorPeriod(ctx, val) 612 613 // calculate delegation rewards 614 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 615 require.NoError(t, err) 616 617 // rewards should be half the tokens 618 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, rewards) 619 620 // commission should be the other half 621 valCommission, err := distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddr) 622 require.NoError(t, err) 623 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, valCommission.Commission) 624 } 625 626 func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { 627 ctrl := gomock.NewController(t) 628 key := storetypes.NewKVStoreKey(disttypes.StoreKey) 629 storeService := runtime.NewKVStoreService(key) 630 testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test")) 631 encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) 632 ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Height: 1}) 633 634 bankKeeper := distrtestutil.NewMockBankKeeper(ctrl) 635 stakingKeeper := distrtestutil.NewMockStakingKeeper(ctrl) 636 accountKeeper := distrtestutil.NewMockAccountKeeper(ctrl) 637 638 accountKeeper.EXPECT().GetModuleAddress("distribution").Return(distrAcc.GetAddress()) 639 stakingKeeper.EXPECT().ValidatorAddressCodec().Return(address.NewBech32Codec(sdk.Bech32PrefixValAddr)).AnyTimes() 640 accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec(sdk.Bech32MainPrefix)).AnyTimes() 641 642 distrKeeper := keeper.NewKeeper( 643 encCfg.Codec, 644 storeService, 645 accountKeeper, 646 bankKeeper, 647 stakingKeeper, 648 "fee_collector", 649 authtypes.NewModuleAddress("gov").String(), 650 ) 651 652 // reset fee pool 653 require.NoError(t, distrKeeper.FeePool.Set(ctx, disttypes.InitialFeePool())) 654 require.NoError(t, distrKeeper.Params.Set(ctx, disttypes.DefaultParams())) 655 656 valPower := int64(100) 657 658 // create validator with 50% commission 659 valAddr := sdk.ValAddress(valConsAddr0) 660 addr := sdk.AccAddress(valAddr) 661 val, err := distrtestutil.CreateValidator(valConsPk0, sdk.TokensFromConsensusPower(valPower, sdk.DefaultPowerReduction)) 662 require.NoError(t, err) 663 val.Commission = stakingtypes.NewCommission(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)) 664 665 // validator and delegation mocks 666 del := stakingtypes.NewDelegation(addr.String(), valAddr.String(), val.DelegatorShares) 667 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(3) 668 stakingKeeper.EXPECT().Delegation(gomock.Any(), addr, valAddr).Return(del, nil) 669 670 // run the necessary hooks manually (given that we are not running an actual staking module) 671 err = distrtestutil.CallCreateValidatorHooks(ctx, distrKeeper, addr, valAddr) 672 require.NoError(t, err) 673 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(2) 674 675 // next block 676 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 677 678 // allocate some rewards 679 initial := math.LegacyNewDecFromInt(sdk.TokensFromConsensusPower(30, sdk.DefaultPowerReduction)) 680 tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}} 681 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 682 683 // slash the validator 684 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 685 distrtestutil.SlashValidator( 686 ctx, 687 valConsAddr0, 688 ctx.BlockHeight(), 689 valPower, 690 math.LegacyNewDecWithPrec(5, 1), 691 &val, 692 &distrKeeper, 693 stakingKeeper, 694 ) 695 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 696 697 // update validator mock 698 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(1) 699 700 // second delegation 701 _, del2, err := distrtestutil.Delegate( 702 ctx, 703 distrKeeper, 704 sdk.AccAddress(valConsAddr1), 705 &val, 706 sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction), 707 nil, 708 stakingKeeper, 709 ) 710 require.NoError(t, err) 711 712 // new delegation mock and update validator mock 713 stakingKeeper.EXPECT().Delegation(gomock.Any(), sdk.AccAddress(valConsAddr1), valAddr).Return(del2, nil) 714 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(1) 715 716 // call necessary hooks to update a delegation 717 err = distrKeeper.Hooks().AfterDelegationModified(ctx, sdk.AccAddress(valConsAddr1), valAddr) 718 require.NoError(t, err) 719 720 // next block 721 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 722 723 // allocate some more rewards 724 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 725 726 // slash the validator again 727 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 728 distrtestutil.SlashValidator( 729 ctx, 730 valConsAddr0, 731 ctx.BlockHeight(), 732 valPower, 733 math.LegacyNewDecWithPrec(5, 1), 734 &val, 735 &distrKeeper, 736 stakingKeeper, 737 ) 738 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) 739 740 // end period 741 endingPeriod, _ := distrKeeper.IncrementValidatorPeriod(ctx, val) 742 743 // calculate delegation rewards for del1 744 rewards, err := distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 745 require.NoError(t, err) 746 747 // rewards for del1 should be 2/3 initial (half initial first period, 1/6 initial second period) 748 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoInt64(2).Add(initial.QuoInt64(6))}}, rewards) 749 750 // calculate delegation rewards for del2 751 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) 752 require.NoError(t, err) 753 754 // rewards for del2 should be initial / 3 755 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoInt64(3)}}, rewards) 756 757 // commission should be equal to initial (twice 50% commission, unaffected by slashing) 758 valCommission, err := distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddr) 759 require.NoError(t, err) 760 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, valCommission.Commission) 761 } 762 763 func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { 764 ctrl := gomock.NewController(t) 765 key := storetypes.NewKVStoreKey(disttypes.StoreKey) 766 storeService := runtime.NewKVStoreService(key) 767 testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test")) 768 encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) 769 ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Height: 1}) 770 771 bankKeeper := distrtestutil.NewMockBankKeeper(ctrl) 772 stakingKeeper := distrtestutil.NewMockStakingKeeper(ctrl) 773 accountKeeper := distrtestutil.NewMockAccountKeeper(ctrl) 774 775 accountKeeper.EXPECT().GetModuleAddress("distribution").Return(distrAcc.GetAddress()) 776 stakingKeeper.EXPECT().ValidatorAddressCodec().Return(address.NewBech32Codec(sdk.Bech32PrefixValAddr)).AnyTimes() 777 accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec(sdk.Bech32MainPrefix)).AnyTimes() 778 779 distrKeeper := keeper.NewKeeper( 780 encCfg.Codec, 781 storeService, 782 accountKeeper, 783 bankKeeper, 784 stakingKeeper, 785 "fee_collector", 786 authtypes.NewModuleAddress("gov").String(), 787 ) 788 789 // reset fee pool 790 require.NoError(t, distrKeeper.FeePool.Set(ctx, disttypes.InitialFeePool())) 791 require.NoError(t, distrKeeper.Params.Set(ctx, disttypes.DefaultParams())) 792 793 // create validator with 50% commission 794 valAddr := sdk.ValAddress(valConsAddr0) 795 addr := sdk.AccAddress(valAddr) 796 val, err := distrtestutil.CreateValidator(valConsPk0, math.NewInt(100)) 797 require.NoError(t, err) 798 val.Commission = stakingtypes.NewCommission(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)) 799 800 // validator and delegation mocks 801 del := stakingtypes.NewDelegation(addr.String(), valAddr.String(), val.DelegatorShares) 802 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(3) 803 stakingKeeper.EXPECT().Delegation(gomock.Any(), addr, valAddr).Return(del, nil).Times(5) 804 805 // run the necessary hooks manually (given that we are not running an actual staking module) 806 err = distrtestutil.CallCreateValidatorHooks(ctx, distrKeeper, addr, valAddr) 807 require.NoError(t, err) 808 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(2) 809 810 // next block 811 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 812 813 // allocate some rewards 814 initial := int64(20) 815 tokens := sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, math.NewInt(initial))} 816 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 817 818 // historical count should be 2 (validator init, delegation init) 819 require.Equal(t, uint64(2), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) 820 821 // second delegation 822 _, del2, err := distrtestutil.Delegate( 823 ctx, 824 distrKeeper, 825 sdk.AccAddress(valConsAddr1), 826 &val, 827 math.NewInt(100), 828 nil, 829 stakingKeeper, 830 ) 831 require.NoError(t, err) 832 833 // new delegation mock and update validator mock 834 stakingKeeper.EXPECT().Delegation(gomock.Any(), sdk.AccAddress(valConsAddr1), valAddr).Return(del2, nil).Times(3) 835 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(6) 836 837 // call necessary hooks to update a delegation 838 err = distrKeeper.Hooks().AfterDelegationModified(ctx, sdk.AccAddress(valConsAddr1), valAddr) 839 require.NoError(t, err) 840 841 // historical count should be 3 (second delegation init) 842 require.Equal(t, uint64(3), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) 843 844 // next block 845 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 846 847 // allocate some more rewards 848 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 849 850 // first delegator withdraws 851 expRewards := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(initial*3/4))} 852 bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, disttypes.ModuleName, addr, expRewards) 853 _, err = distrKeeper.WithdrawDelegationRewards(ctx, addr, valAddr) 854 require.NoError(t, err) 855 856 // second delegator withdraws 857 expRewards = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(initial*1/4))} 858 bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, disttypes.ModuleName, sdk.AccAddress(valConsAddr1), expRewards) 859 _, err = distrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valConsAddr1), valAddr) 860 require.NoError(t, err) 861 862 // historical count should be 3 (validator init + two delegations) 863 require.Equal(t, uint64(3), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) 864 865 // validator withdraws commission 866 expCommission := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(initial))} 867 bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, disttypes.ModuleName, addr, expCommission) 868 _, err = distrKeeper.WithdrawValidatorCommission(ctx, valAddr) 869 require.NoError(t, err) 870 871 // end period 872 endingPeriod, _ := distrKeeper.IncrementValidatorPeriod(ctx, val) 873 874 // calculate delegation rewards for del1 875 rewards, err := distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 876 require.NoError(t, err) 877 878 // rewards for del1 should be zero 879 require.True(t, rewards.IsZero()) 880 881 // calculate delegation rewards for del2 882 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) 883 require.NoError(t, err) 884 885 // rewards for del2 should be zero 886 require.True(t, rewards.IsZero()) 887 888 // commission should be zero 889 valCommission, err := distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddr) 890 require.NoError(t, err) 891 require.True(t, valCommission.Commission.IsZero()) 892 893 // next block 894 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 895 896 // allocate some more rewards 897 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 898 899 // first delegator withdraws again 900 expCommission = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(initial*1/4))} 901 bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, disttypes.ModuleName, addr, expCommission) 902 _, err = distrKeeper.WithdrawDelegationRewards(ctx, addr, valAddr) 903 require.NoError(t, err) 904 905 // end period 906 endingPeriod, _ = distrKeeper.IncrementValidatorPeriod(ctx, val) 907 908 // calculate delegation rewards for del1 909 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 910 require.NoError(t, err) 911 912 // rewards for del1 should be zero 913 require.True(t, rewards.IsZero()) 914 915 // calculate delegation rewards for del2 916 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) 917 require.NoError(t, err) 918 919 // rewards for del2 should be 1/4 initial 920 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 4)}}, rewards) 921 922 // commission should be half initial 923 valCommission, err = distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddr) 924 require.NoError(t, err) 925 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 2)}}, valCommission.Commission) 926 927 // next block 928 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 929 930 // allocate some more rewards 931 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 932 933 // withdraw commission 934 expCommission = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(initial))} 935 bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, disttypes.ModuleName, addr, expCommission) 936 _, err = distrKeeper.WithdrawValidatorCommission(ctx, valAddr) 937 require.NoError(t, err) 938 939 // end period 940 endingPeriod, _ = distrKeeper.IncrementValidatorPeriod(ctx, val) 941 942 // calculate delegation rewards for del1 943 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) 944 require.NoError(t, err) 945 946 // rewards for del1 should be 1/4 initial 947 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 4)}}, rewards) 948 949 // calculate delegation rewards for del2 950 rewards, err = distrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) 951 require.NoError(t, err) 952 953 // rewards for del2 should be 1/2 initial 954 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 2)}}, rewards) 955 956 // commission should be zero 957 valCommission, err = distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddr) 958 require.NoError(t, err) 959 require.True(t, valCommission.Commission.IsZero()) 960 } 961 962 func Test100PercentCommissionReward(t *testing.T) { 963 ctrl := gomock.NewController(t) 964 key := storetypes.NewKVStoreKey(disttypes.StoreKey) 965 storeService := runtime.NewKVStoreService(key) 966 testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test")) 967 encCfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}) 968 ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Height: 1}) 969 970 bankKeeper := distrtestutil.NewMockBankKeeper(ctrl) 971 stakingKeeper := distrtestutil.NewMockStakingKeeper(ctrl) 972 accountKeeper := distrtestutil.NewMockAccountKeeper(ctrl) 973 974 accountKeeper.EXPECT().GetModuleAddress("distribution").Return(distrAcc.GetAddress()) 975 stakingKeeper.EXPECT().ValidatorAddressCodec().Return(address.NewBech32Codec(sdk.Bech32PrefixValAddr)).AnyTimes() 976 accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec(sdk.Bech32MainPrefix)).AnyTimes() 977 978 distrKeeper := keeper.NewKeeper( 979 encCfg.Codec, 980 storeService, 981 accountKeeper, 982 bankKeeper, 983 stakingKeeper, 984 "fee_collector", 985 authtypes.NewModuleAddress("gov").String(), 986 ) 987 988 // reset fee pool 989 require.NoError(t, distrKeeper.FeePool.Set(ctx, disttypes.InitialFeePool())) 990 require.NoError(t, distrKeeper.Params.Set(ctx, disttypes.DefaultParams())) 991 992 // create validator with 50% commission 993 valAddr := sdk.ValAddress(valConsAddr0) 994 addr := sdk.AccAddress(valAddr) 995 val, err := distrtestutil.CreateValidator(valConsPk0, math.NewInt(100)) 996 require.NoError(t, err) 997 val.Commission = stakingtypes.NewCommission(math.LegacyNewDecWithPrec(10, 1), math.LegacyNewDecWithPrec(10, 1), math.LegacyNewDec(0)) 998 999 // validator and delegation mocks 1000 del := stakingtypes.NewDelegation(addr.String(), valAddr.String(), val.DelegatorShares) 1001 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(3) 1002 stakingKeeper.EXPECT().Delegation(gomock.Any(), addr, valAddr).Return(del, nil).Times(3) 1003 1004 // run the necessary hooks manually (given that we are not running an actual staking module) 1005 err = distrtestutil.CallCreateValidatorHooks(ctx, distrKeeper, addr, valAddr) 1006 require.NoError(t, err) 1007 stakingKeeper.EXPECT().Validator(gomock.Any(), valAddr).Return(val, nil).Times(2) 1008 1009 // next block 1010 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 1011 1012 // allocate some rewards 1013 initial := int64(20) 1014 tokens := sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, math.NewInt(initial))} 1015 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 1016 1017 // next block 1018 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 1019 1020 // allocate some rewards 1021 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 1022 1023 // next block 1024 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 1025 1026 // allocate some more rewards 1027 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 1028 1029 // next block 1030 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 1031 1032 // allocate some more rewards 1033 require.NoError(t, distrKeeper.AllocateTokensToValidator(ctx, val, tokens)) 1034 1035 rewards, err := distrKeeper.WithdrawDelegationRewards(ctx, addr, valAddr) 1036 require.NoError(t, err) 1037 1038 zeroRewards := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, math.ZeroInt())} 1039 require.True(t, rewards.Equal(zeroRewards)) 1040 1041 events := ctx.EventManager().Events() 1042 lastEvent := events[len(events)-1] 1043 1044 var hasValue bool 1045 for _, attr := range lastEvent.Attributes { 1046 if attr.Key == "amount" && attr.Value == "0stake" { 1047 hasValue = true 1048 } 1049 } 1050 require.True(t, hasValue) 1051 }