github.com/Finschia/finschia-sdk@v0.48.1/x/distribution/keeper/delegation_test.go (about)

     1  package keeper_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/require"
     7  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
     8  
     9  	"github.com/Finschia/finschia-sdk/simapp"
    10  	sdk "github.com/Finschia/finschia-sdk/types"
    11  	"github.com/Finschia/finschia-sdk/x/staking"
    12  	"github.com/Finschia/finschia-sdk/x/staking/teststaking"
    13  	stakingtypes "github.com/Finschia/finschia-sdk/x/staking/types"
    14  )
    15  
    16  func TestCalculateRewardsBasic(t *testing.T) {
    17  	app := simapp.Setup(false)
    18  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
    19  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
    20  
    21  	addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000))
    22  	valAddrs := simapp.ConvertAddrsToValAddrs(addr)
    23  
    24  	// create validator with 50% commission
    25  	tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
    26  	tstaking.CreateValidator(valAddrs[0], valConsPk1, sdk.NewInt(100), true)
    27  
    28  	// end block to bond validator and start new block
    29  	staking.EndBlocker(ctx, app.StakingKeeper)
    30  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
    31  	tstaking.Ctx = ctx
    32  
    33  	// fetch validator and delegation
    34  	val := app.StakingKeeper.Validator(ctx, valAddrs[0])
    35  	del := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
    36  
    37  	// historical count should be 2 (once for validator init, once for delegation init)
    38  	require.Equal(t, uint64(2), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx))
    39  
    40  	// end period
    41  	endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
    42  
    43  	// historical count should be 2 still
    44  	require.Equal(t, uint64(2), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx))
    45  
    46  	// calculate delegation rewards
    47  	rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod)
    48  
    49  	// rewards should be zero
    50  	require.True(t, rewards.IsZero())
    51  
    52  	// allocate some rewards
    53  	initial := int64(10)
    54  	tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial)}}
    55  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
    56  
    57  	// end period
    58  	endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
    59  
    60  	// calculate delegation rewards
    61  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod)
    62  
    63  	// rewards should be half the tokens
    64  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, rewards)
    65  
    66  	// commission should be the other half
    67  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission)
    68  }
    69  
    70  func TestCalculateRewardsAfterSlash(t *testing.T) {
    71  	app := simapp.Setup(false)
    72  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
    73  
    74  	addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(100000000))
    75  	valAddrs := simapp.ConvertAddrsToValAddrs(addr)
    76  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
    77  
    78  	// create validator with 50% commission
    79  	tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
    80  	valPower := int64(100)
    81  	tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk1, valPower, true)
    82  
    83  	// end block to bond validator
    84  	staking.EndBlocker(ctx, app.StakingKeeper)
    85  
    86  	// next block
    87  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
    88  
    89  	// fetch validator and delegation
    90  	val := app.StakingKeeper.Validator(ctx, valAddrs[0])
    91  	del := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
    92  
    93  	// end period
    94  	endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
    95  
    96  	// calculate delegation rewards
    97  	rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod)
    98  
    99  	// rewards should be zero
   100  	require.True(t, rewards.IsZero())
   101  
   102  	// start out block height
   103  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   104  
   105  	// slash the validator by 50%
   106  	app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1))
   107  
   108  	// retrieve validator
   109  	val = app.StakingKeeper.Validator(ctx, valAddrs[0])
   110  
   111  	// increase block height
   112  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   113  
   114  	// allocate some rewards
   115  	initial := app.StakingKeeper.TokensFromConsensusPower(ctx, 10)
   116  	tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}}
   117  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   118  
   119  	// end period
   120  	endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
   121  
   122  	// calculate delegation rewards
   123  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod)
   124  
   125  	// rewards should be half the tokens
   126  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoRaw(2).ToDec()}}, rewards)
   127  
   128  	// commission should be the other half
   129  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoRaw(2).ToDec()}},
   130  		app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission)
   131  }
   132  
   133  func TestCalculateRewardsAfterManySlashes(t *testing.T) {
   134  	app := simapp.Setup(false)
   135  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   136  
   137  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   138  	addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(100000000))
   139  	valAddrs := simapp.ConvertAddrsToValAddrs(addr)
   140  
   141  	// create validator with 50% commission
   142  	valPower := int64(100)
   143  	tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
   144  	tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk1, valPower, true)
   145  
   146  	// end block to bond validator
   147  	staking.EndBlocker(ctx, app.StakingKeeper)
   148  
   149  	// next block
   150  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   151  
   152  	// fetch validator and delegation
   153  	val := app.StakingKeeper.Validator(ctx, valAddrs[0])
   154  	del := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
   155  
   156  	// end period
   157  	endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
   158  
   159  	// calculate delegation rewards
   160  	rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod)
   161  
   162  	// rewards should be zero
   163  	require.True(t, rewards.IsZero())
   164  
   165  	// start out block height
   166  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   167  
   168  	// slash the validator by 50%
   169  	app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1))
   170  
   171  	// fetch the validator again
   172  	val = app.StakingKeeper.Validator(ctx, valAddrs[0])
   173  
   174  	// increase block height
   175  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   176  
   177  	// allocate some rewards
   178  	initial := app.StakingKeeper.TokensFromConsensusPower(ctx, 10)
   179  	tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}}
   180  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   181  
   182  	// slash the validator by 50% again
   183  	app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), valPower/2, sdk.NewDecWithPrec(5, 1))
   184  
   185  	// fetch the validator again
   186  	val = app.StakingKeeper.Validator(ctx, valAddrs[0])
   187  
   188  	// increase block height
   189  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   190  
   191  	// allocate some more rewards
   192  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   193  
   194  	// end period
   195  	endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
   196  
   197  	// calculate delegation rewards
   198  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod)
   199  
   200  	// rewards should be half the tokens
   201  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}}, rewards)
   202  
   203  	// commission should be the other half
   204  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.ToDec()}},
   205  		app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission)
   206  }
   207  
   208  func TestCalculateRewardsMultiDelegator(t *testing.T) {
   209  	app := simapp.Setup(false)
   210  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   211  
   212  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   213  	addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(100000000))
   214  	valAddrs := simapp.ConvertAddrsToValAddrs(addr)
   215  
   216  	// create validator with 50% commission
   217  	tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
   218  	tstaking.CreateValidator(valAddrs[0], valConsPk1, sdk.NewInt(100), true)
   219  
   220  	// end block to bond validator
   221  	staking.EndBlocker(ctx, app.StakingKeeper)
   222  
   223  	// next block
   224  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   225  
   226  	// fetch validator and delegation
   227  	val := app.StakingKeeper.Validator(ctx, valAddrs[0])
   228  	del1 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
   229  
   230  	// allocate some rewards
   231  	initial := int64(20)
   232  	tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial)}}
   233  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   234  
   235  	// second delegation
   236  	tstaking.Ctx = ctx
   237  	tstaking.Delegate(sdk.AccAddress(valAddrs[1]), valAddrs[0], sdk.NewInt(100))
   238  	del2 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0])
   239  
   240  	// fetch updated validator
   241  	val = app.StakingKeeper.Validator(ctx, valAddrs[0])
   242  
   243  	// end block
   244  	staking.EndBlocker(ctx, app.StakingKeeper)
   245  
   246  	// next block
   247  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   248  
   249  	// allocate some more rewards
   250  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   251  
   252  	// end period
   253  	endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
   254  
   255  	// calculate delegation rewards for del1
   256  	rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod)
   257  
   258  	// rewards for del1 should be 3/4 initial
   259  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial * 3 / 4)}}, rewards)
   260  
   261  	// calculate delegation rewards for del2
   262  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod)
   263  
   264  	// rewards for del2 should be 1/4 initial
   265  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial * 1 / 4)}}, rewards)
   266  
   267  	// commission should be equal to initial (50% twice)
   268  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial)}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission)
   269  }
   270  
   271  func TestWithdrawDelegationRewardsBasic(t *testing.T) {
   272  	app := simapp.Setup(false)
   273  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   274  
   275  	balancePower := int64(1000)
   276  	balanceTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, balancePower)
   277  	addr := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(1000000000))
   278  	valAddrs := simapp.ConvertAddrsToValAddrs(addr)
   279  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   280  
   281  	// set module account coins
   282  	distrAcc := app.DistrKeeper.GetDistributionAccount(ctx)
   283  	require.NoError(t, simapp.FundModuleAccount(app, ctx, distrAcc.GetName(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens))))
   284  	app.AccountKeeper.SetModuleAccount(ctx, distrAcc)
   285  
   286  	// create validator with 50% commission
   287  	power := int64(100)
   288  	tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
   289  	valTokens := tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk1, power, true)
   290  
   291  	// assert correct initial balance
   292  	expTokens := balanceTokens.Sub(valTokens)
   293  	require.Equal(t,
   294  		sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, expTokens)},
   295  		app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])),
   296  	)
   297  
   298  	// end block to bond validator
   299  	staking.EndBlocker(ctx, app.StakingKeeper)
   300  
   301  	// next block
   302  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   303  
   304  	// fetch validator and delegation
   305  	val := app.StakingKeeper.Validator(ctx, valAddrs[0])
   306  
   307  	// allocate some rewards
   308  	initial := app.StakingKeeper.TokensFromConsensusPower(ctx, 10)
   309  	tokens := sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, initial)}
   310  
   311  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   312  
   313  	// historical count should be 2 (initial + latest for delegation)
   314  	require.Equal(t, uint64(2), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx))
   315  
   316  	// withdraw rewards
   317  	_, err := app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
   318  	require.Nil(t, err)
   319  
   320  	// historical count should still be 2 (added one record, cleared one)
   321  	require.Equal(t, uint64(2), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx))
   322  
   323  	// assert correct balance
   324  	exp := balanceTokens.Sub(valTokens).Add(initial.QuoRaw(2))
   325  	require.Equal(t,
   326  		sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, exp)},
   327  		app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])),
   328  	)
   329  
   330  	// withdraw commission
   331  	_, err = app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0])
   332  	require.Nil(t, err)
   333  }
   334  
   335  func TestWithdrawDelegationZeroRewards(t *testing.T) {
   336  	app := simapp.Setup(false)
   337  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   338  
   339  	balancePower := int64(1000)
   340  	balanceTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, balancePower)
   341  	addr := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(1000000000))
   342  	valAddrs := simapp.ConvertAddrsToValAddrs(addr)
   343  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   344  
   345  	// set module account coins
   346  	distrAcc := app.DistrKeeper.GetDistributionAccount(ctx)
   347  	require.NoError(t, simapp.FundModuleAccount(app, ctx, distrAcc.GetName(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens))))
   348  	app.AccountKeeper.SetModuleAccount(ctx, distrAcc)
   349  
   350  	// create validator with 50% commission
   351  	power := int64(100)
   352  	tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
   353  	_ = tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk1, power, true)
   354  
   355  	// withdraw rewards -- should be 0
   356  	amount, err := app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
   357  	require.NoError(t, err)
   358  	require.True(t, amount.IsZero(), "expected withdraw rewards to be zero")
   359  	require.True(t, amount.IsValid(), "expected returned coins to be valid")
   360  }
   361  
   362  func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) {
   363  	app := simapp.Setup(false)
   364  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   365  
   366  	addr := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(1000000000))
   367  	valAddrs := simapp.ConvertAddrsToValAddrs(addr)
   368  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   369  
   370  	// create validator with 50% commission
   371  	valPower := int64(100)
   372  	tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
   373  	tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk1, valPower, true)
   374  
   375  	// end block to bond validator
   376  	staking.EndBlocker(ctx, app.StakingKeeper)
   377  
   378  	// next block
   379  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   380  
   381  	// fetch validator and delegation
   382  	val := app.StakingKeeper.Validator(ctx, valAddrs[0])
   383  	del := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
   384  
   385  	// end period
   386  	endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
   387  
   388  	// calculate delegation rewards
   389  	rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod)
   390  
   391  	// rewards should be zero
   392  	require.True(t, rewards.IsZero())
   393  
   394  	// start out block height
   395  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   396  
   397  	// allocate some rewards
   398  	initial := app.StakingKeeper.TokensFromConsensusPower(ctx, 10).ToDec()
   399  	tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}
   400  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   401  
   402  	// slash the validator by 50%
   403  	app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1))
   404  
   405  	// slash the validator by 50% again
   406  	app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), valPower/2, sdk.NewDecWithPrec(5, 1))
   407  
   408  	// fetch the validator again
   409  	val = app.StakingKeeper.Validator(ctx, valAddrs[0])
   410  
   411  	// increase block height
   412  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   413  
   414  	// allocate some more rewards
   415  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   416  
   417  	// end period
   418  	endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
   419  
   420  	// calculate delegation rewards
   421  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod)
   422  
   423  	// rewards should be half the tokens
   424  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, rewards)
   425  
   426  	// commission should be the other half
   427  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission)
   428  }
   429  
   430  func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) {
   431  	app := simapp.Setup(false)
   432  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   433  
   434  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   435  	addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000000000))
   436  	valAddrs := simapp.ConvertAddrsToValAddrs(addr)
   437  
   438  	// create validator with 50% commission
   439  	tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
   440  	valPower := int64(100)
   441  	tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk1, valPower, true)
   442  
   443  	// end block to bond validator
   444  	staking.EndBlocker(ctx, app.StakingKeeper)
   445  
   446  	// next block
   447  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   448  
   449  	// fetch validator and delegation
   450  	val := app.StakingKeeper.Validator(ctx, valAddrs[0])
   451  	del1 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
   452  
   453  	// allocate some rewards
   454  	initial := app.StakingKeeper.TokensFromConsensusPower(ctx, 30).ToDec()
   455  	tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}
   456  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   457  
   458  	// slash the validator
   459  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   460  	app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1))
   461  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   462  
   463  	// second delegation
   464  	tstaking.DelegateWithPower(sdk.AccAddress(valAddrs[1]), valAddrs[0], 100)
   465  
   466  	del2 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0])
   467  
   468  	// end block
   469  	staking.EndBlocker(ctx, app.StakingKeeper)
   470  
   471  	// next block
   472  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   473  
   474  	// allocate some more rewards
   475  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   476  
   477  	// slash the validator again
   478  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   479  	app.StakingKeeper.Slash(ctx, valConsAddr1, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1))
   480  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
   481  
   482  	// fetch updated validator
   483  	val = app.StakingKeeper.Validator(ctx, valAddrs[0])
   484  
   485  	// end period
   486  	endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
   487  
   488  	// calculate delegation rewards for del1
   489  	rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod)
   490  
   491  	// rewards for del1 should be 2/3 initial (half initial first period, 1/6 initial second period)
   492  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoInt64(2).Add(initial.QuoInt64(6))}}, rewards)
   493  
   494  	// calculate delegation rewards for del2
   495  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod)
   496  
   497  	// rewards for del2 should be initial / 3
   498  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoInt64(3)}}, rewards)
   499  
   500  	// commission should be equal to initial (twice 50% commission, unaffected by slashing)
   501  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission)
   502  }
   503  
   504  func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) {
   505  	app := simapp.Setup(false)
   506  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   507  
   508  	tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper)
   509  	addr := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1000000000))
   510  	valAddrs := simapp.ConvertAddrsToValAddrs(addr)
   511  	initial := int64(20)
   512  
   513  	// set module account coins
   514  	distrAcc := app.DistrKeeper.GetDistributionAccount(ctx)
   515  	require.NoError(t, simapp.FundModuleAccount(app, ctx, distrAcc.GetName(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)))))
   516  	app.AccountKeeper.SetModuleAccount(ctx, distrAcc)
   517  
   518  	tokens := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDec(initial))}
   519  
   520  	// create validator with 50% commission
   521  	tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
   522  	tstaking.CreateValidator(valAddrs[0], valConsPk1, sdk.NewInt(100), true)
   523  
   524  	// end block to bond validator
   525  	staking.EndBlocker(ctx, app.StakingKeeper)
   526  
   527  	// next block
   528  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   529  
   530  	// fetch validator and delegation
   531  	val := app.StakingKeeper.Validator(ctx, valAddrs[0])
   532  	del1 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
   533  
   534  	// allocate some rewards
   535  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   536  
   537  	// historical count should be 2 (validator init, delegation init)
   538  	require.Equal(t, uint64(2), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx))
   539  
   540  	// second delegation
   541  	tstaking.Delegate(sdk.AccAddress(valAddrs[1]), valAddrs[0], sdk.NewInt(100))
   542  
   543  	// historical count should be 3 (second delegation init)
   544  	require.Equal(t, uint64(3), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx))
   545  
   546  	// fetch updated validator
   547  	val = app.StakingKeeper.Validator(ctx, valAddrs[0])
   548  	del2 := app.StakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0])
   549  
   550  	// end block
   551  	staking.EndBlocker(ctx, app.StakingKeeper)
   552  
   553  	// next block
   554  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   555  
   556  	// allocate some more rewards
   557  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   558  
   559  	// first delegator withdraws
   560  	_, err := app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
   561  	require.NoError(t, err)
   562  
   563  	// second delegator withdraws
   564  	_, err = app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0])
   565  	require.NoError(t, err)
   566  
   567  	// historical count should be 3 (validator init + two delegations)
   568  	require.Equal(t, uint64(3), app.DistrKeeper.GetValidatorHistoricalReferenceCount(ctx))
   569  
   570  	// validator withdraws commission
   571  	_, err = app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0])
   572  	require.NoError(t, err)
   573  
   574  	// end period
   575  	endingPeriod := app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
   576  
   577  	// calculate delegation rewards for del1
   578  	rewards := app.DistrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod)
   579  
   580  	// rewards for del1 should be zero
   581  	require.True(t, rewards.IsZero())
   582  
   583  	// calculate delegation rewards for del2
   584  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod)
   585  
   586  	// rewards for del2 should be zero
   587  	require.True(t, rewards.IsZero())
   588  
   589  	// commission should be zero
   590  	require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero())
   591  
   592  	// next block
   593  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   594  
   595  	// allocate some more rewards
   596  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   597  
   598  	// first delegator withdraws again
   599  	_, err = app.DistrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0])
   600  	require.NoError(t, err)
   601  
   602  	// end period
   603  	endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
   604  
   605  	// calculate delegation rewards for del1
   606  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod)
   607  
   608  	// rewards for del1 should be zero
   609  	require.True(t, rewards.IsZero())
   610  
   611  	// calculate delegation rewards for del2
   612  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod)
   613  
   614  	// rewards for del2 should be 1/4 initial
   615  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 4)}}, rewards)
   616  
   617  	// commission should be half initial
   618  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission)
   619  
   620  	// next block
   621  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   622  
   623  	// allocate some more rewards
   624  	app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens)
   625  
   626  	// withdraw commission
   627  	_, err = app.DistrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0])
   628  	require.NoError(t, err)
   629  
   630  	// end period
   631  	endingPeriod = app.DistrKeeper.IncrementValidatorPeriod(ctx, val)
   632  
   633  	// calculate delegation rewards for del1
   634  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod)
   635  
   636  	// rewards for del1 should be 1/4 initial
   637  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 4)}}, rewards)
   638  
   639  	// calculate delegation rewards for del2
   640  	rewards = app.DistrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod)
   641  
   642  	// rewards for del2 should be 1/2 initial
   643  	require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(initial / 2)}}, rewards)
   644  
   645  	// commission should be zero
   646  	require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero())
   647  }