2018-10-04 18:37:40 -07:00
|
|
|
package keeper
|
|
|
|
|
2018-10-09 10:58:59 -07:00
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
2018-12-10 06:27:25 -08:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2018-10-10 14:43:47 -07:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2019-01-11 12:08:01 -08:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/staking"
|
2018-10-09 10:58:59 -07:00
|
|
|
)
|
2018-10-04 18:37:40 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
func TestCalculateRewardsBasic(t *testing.T) {
|
|
|
|
ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000)
|
|
|
|
sh := staking.NewHandler(sk)
|
|
|
|
|
|
|
|
// initialize state
|
|
|
|
k.SetOutstandingRewards(ctx, sdk.DecCoins{})
|
|
|
|
|
|
|
|
// create validator with 50% commission
|
|
|
|
commission := staking.NewCommissionMsg(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
|
|
|
|
msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1,
|
2019-02-13 15:01:50 -08:00
|
|
|
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt())
|
2019-01-16 13:38:05 -08:00
|
|
|
require.True(t, sh(ctx, msg).IsOK())
|
|
|
|
|
|
|
|
// end block to bond validator
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// fetch validator and delegation
|
|
|
|
val := sk.Validator(ctx, valOpAddr1)
|
|
|
|
del := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
|
|
|
|
2019-01-23 03:37:03 -08:00
|
|
|
// historical count should be 2 (once for validator init, once for delegation init)
|
2019-01-24 13:01:32 -08:00
|
|
|
require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx))
|
2019-01-23 03:37:03 -08:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// end period
|
|
|
|
endingPeriod := k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
2019-01-24 13:01:32 -08:00
|
|
|
// historical count should be 2 still
|
|
|
|
require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx))
|
2019-01-23 03:37:03 -08:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// calculate delegation rewards
|
|
|
|
rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
|
|
|
|
|
|
|
// rewards should be zero
|
|
|
|
require.True(t, rewards.IsZero())
|
|
|
|
|
|
|
|
// allocate some rewards
|
|
|
|
initial := int64(10)
|
2019-02-13 15:01:50 -08:00
|
|
|
tokens := sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial)}}
|
2019-01-16 13:38:05 -08:00
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod = k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
|
|
|
|
|
|
|
// rewards should be half the tokens
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial / 2)}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// commission should be the other half
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial / 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1))
|
2018-10-10 23:14:06 -07:00
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
func TestCalculateRewardsAfterSlash(t *testing.T) {
|
|
|
|
ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000)
|
|
|
|
sh := staking.NewHandler(sk)
|
|
|
|
|
|
|
|
// initialize state
|
|
|
|
k.SetOutstandingRewards(ctx, sdk.DecCoins{})
|
|
|
|
|
|
|
|
// create validator with 50% commission
|
|
|
|
commission := staking.NewCommissionMsg(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
|
2019-02-05 21:30:48 -08:00
|
|
|
valPower := int64(100)
|
2019-02-13 15:01:50 -08:00
|
|
|
valTokens := sdk.TokensFromTendermintPower(valPower)
|
2019-01-16 13:38:05 -08:00
|
|
|
msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1,
|
2019-02-13 15:01:50 -08:00
|
|
|
sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt())
|
2019-02-05 21:30:48 -08:00
|
|
|
got := sh(ctx, msg)
|
|
|
|
require.True(t, got.IsOK(), "%v", got)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// end block to bond validator
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// fetch validator and delegation
|
|
|
|
val := sk.Validator(ctx, valOpAddr1)
|
|
|
|
del := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod := k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards
|
|
|
|
rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
|
|
|
|
|
|
|
// rewards should be zero
|
|
|
|
require.True(t, rewards.IsZero())
|
|
|
|
|
|
|
|
// start out block height
|
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
|
|
|
|
|
|
|
// slash the validator by 50%
|
2019-02-05 21:30:48 -08:00
|
|
|
sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1))
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// retrieve validator
|
|
|
|
val = sk.Validator(ctx, valOpAddr1)
|
|
|
|
|
|
|
|
// increase block height
|
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
|
|
|
|
|
|
|
// allocate some rewards
|
2019-02-13 15:01:50 -08:00
|
|
|
initial := sdk.TokensFromTendermintPower(10)
|
|
|
|
tokens := sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDecFromInt(initial)}}
|
2019-01-16 13:38:05 -08:00
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod = k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
|
|
|
|
|
|
|
// rewards should be half the tokens
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDecFromInt(initial.DivRaw(2))}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// commission should be the other half
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDecFromInt(initial.DivRaw(2))}},
|
2019-02-05 21:30:48 -08:00
|
|
|
k.GetValidatorAccumulatedCommission(ctx, valOpAddr1))
|
2018-10-04 18:37:40 -07:00
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
func TestCalculateRewardsAfterManySlashes(t *testing.T) {
|
|
|
|
ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000)
|
|
|
|
sh := staking.NewHandler(sk)
|
|
|
|
|
|
|
|
// initialize state
|
|
|
|
k.SetOutstandingRewards(ctx, sdk.DecCoins{})
|
|
|
|
|
|
|
|
// create validator with 50% commission
|
2019-02-05 21:30:48 -08:00
|
|
|
power := int64(100)
|
2019-02-13 15:01:50 -08:00
|
|
|
valTokens := sdk.TokensFromTendermintPower(power)
|
2019-01-16 13:38:05 -08:00
|
|
|
commission := staking.NewCommissionMsg(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
|
|
|
|
msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1,
|
2019-02-13 15:01:50 -08:00
|
|
|
sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt())
|
2019-01-16 13:38:05 -08:00
|
|
|
require.True(t, sh(ctx, msg).IsOK())
|
|
|
|
|
|
|
|
// end block to bond validator
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// fetch validator and delegation
|
|
|
|
val := sk.Validator(ctx, valOpAddr1)
|
|
|
|
del := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod := k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards
|
|
|
|
rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
|
|
|
|
|
|
|
// rewards should be zero
|
|
|
|
require.True(t, rewards.IsZero())
|
|
|
|
|
|
|
|
// start out block height
|
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
|
|
|
|
|
|
|
// slash the validator by 50%
|
2019-02-05 21:30:48 -08:00
|
|
|
sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1))
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// fetch the validator again
|
|
|
|
val = sk.Validator(ctx, valOpAddr1)
|
|
|
|
|
|
|
|
// increase block height
|
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
|
|
|
|
|
|
|
// allocate some rewards
|
2019-02-13 15:01:50 -08:00
|
|
|
initial := sdk.TokensFromTendermintPower(10)
|
|
|
|
tokens := sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDecFromInt(initial)}}
|
2019-01-16 13:38:05 -08:00
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// slash the validator by 50% again
|
2019-02-05 21:30:48 -08:00
|
|
|
sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power/2, sdk.NewDecWithPrec(5, 1))
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// fetch the validator again
|
|
|
|
val = sk.Validator(ctx, valOpAddr1)
|
|
|
|
|
|
|
|
// increase block height
|
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
|
|
|
|
|
|
|
// allocate some more rewards
|
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod = k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
|
|
|
|
|
|
|
// rewards should be half the tokens
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDecFromInt(initial)}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// commission should be the other half
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDecFromInt(initial)}},
|
2019-02-05 21:30:48 -08:00
|
|
|
k.GetValidatorAccumulatedCommission(ctx, valOpAddr1))
|
2018-10-12 02:37:30 -07:00
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
func TestCalculateRewardsMultiDelegator(t *testing.T) {
|
|
|
|
ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000)
|
|
|
|
sh := staking.NewHandler(sk)
|
|
|
|
|
|
|
|
// initialize state
|
|
|
|
k.SetOutstandingRewards(ctx, sdk.DecCoins{})
|
|
|
|
|
|
|
|
// create validator with 50% commission
|
|
|
|
commission := staking.NewCommissionMsg(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
|
|
|
|
msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1,
|
2019-02-13 15:01:50 -08:00
|
|
|
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt())
|
2019-01-16 13:38:05 -08:00
|
|
|
require.True(t, sh(ctx, msg).IsOK())
|
|
|
|
|
|
|
|
// end block to bond validator
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// fetch validator and delegation
|
|
|
|
val := sk.Validator(ctx, valOpAddr1)
|
|
|
|
del1 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
|
|
|
|
|
|
|
// allocate some rewards
|
|
|
|
initial := int64(20)
|
2019-02-13 15:01:50 -08:00
|
|
|
tokens := sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial)}}
|
2019-01-16 13:38:05 -08:00
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// second delegation
|
2019-02-13 15:01:50 -08:00
|
|
|
msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)))
|
2019-01-16 13:38:05 -08:00
|
|
|
require.True(t, sh(ctx, msg2).IsOK())
|
|
|
|
del2 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1)
|
|
|
|
|
|
|
|
// fetch updated validator
|
|
|
|
val = sk.Validator(ctx, valOpAddr1)
|
|
|
|
|
|
|
|
// end block
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// allocate some more rewards
|
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod := k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards for del1
|
|
|
|
rewards := k.calculateDelegationRewards(ctx, val, del1, endingPeriod)
|
|
|
|
|
|
|
|
// rewards for del1 should be 3/4 initial
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial * 3 / 4)}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// calculate delegation rewards for del2
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del2, endingPeriod)
|
|
|
|
|
|
|
|
// rewards for del2 should be 1/4 initial
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial * 1 / 4)}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// commission should be equal to initial (50% twice)
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1))
|
2018-10-04 18:37:40 -07:00
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
func TestWithdrawDelegationRewardsBasic(t *testing.T) {
|
2019-02-05 21:30:48 -08:00
|
|
|
balancePower := int64(1000)
|
2019-02-13 15:01:50 -08:00
|
|
|
balanceTokens := sdk.TokensFromTendermintPower(balancePower)
|
2019-02-05 21:30:48 -08:00
|
|
|
ctx, ak, k, sk, _ := CreateTestInputDefault(t, false, balancePower)
|
2019-01-16 13:38:05 -08:00
|
|
|
sh := staking.NewHandler(sk)
|
|
|
|
|
|
|
|
// initialize state
|
|
|
|
k.SetOutstandingRewards(ctx, sdk.DecCoins{})
|
|
|
|
|
|
|
|
// create validator with 50% commission
|
2019-02-05 21:30:48 -08:00
|
|
|
power := int64(100)
|
2019-02-13 15:01:50 -08:00
|
|
|
valTokens := sdk.TokensFromTendermintPower(power)
|
2019-01-16 13:38:05 -08:00
|
|
|
commission := staking.NewCommissionMsg(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
|
|
|
|
msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1,
|
2019-02-13 15:01:50 -08:00
|
|
|
sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt())
|
2019-01-16 13:38:05 -08:00
|
|
|
require.True(t, sh(ctx, msg).IsOK())
|
|
|
|
|
|
|
|
// assert correct initial balance
|
2019-02-05 21:30:48 -08:00
|
|
|
expTokens := balanceTokens.Sub(valTokens)
|
|
|
|
require.Equal(t,
|
2019-02-13 15:01:50 -08:00
|
|
|
sdk.Coins{{sdk.DefaultBondDenom, expTokens}},
|
2019-02-05 21:30:48 -08:00
|
|
|
ak.GetAccount(ctx, sdk.AccAddress(valOpAddr1)).GetCoins())
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// end block to bond validator
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// set zero outstanding rewards
|
|
|
|
k.SetOutstandingRewards(ctx, sdk.DecCoins{})
|
|
|
|
|
|
|
|
// fetch validator and delegation
|
|
|
|
val := sk.Validator(ctx, valOpAddr1)
|
|
|
|
|
|
|
|
// allocate some rewards
|
2019-02-13 15:01:50 -08:00
|
|
|
initial := sdk.TokensFromTendermintPower(10)
|
|
|
|
tokens := sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDecFromInt(initial)}}
|
2019-01-16 13:38:05 -08:00
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
2019-01-23 03:37:03 -08:00
|
|
|
// historical count should be 2 (initial + latest for delegation)
|
2019-01-24 13:01:32 -08:00
|
|
|
require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx))
|
2019-01-23 03:37:03 -08:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// withdraw rewards
|
|
|
|
require.Nil(t, k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1))
|
|
|
|
|
2019-01-23 03:37:03 -08:00
|
|
|
// historical count should still be 2 (added one record, cleared one)
|
2019-01-24 13:01:32 -08:00
|
|
|
require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx))
|
2019-01-23 03:37:03 -08:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// assert correct balance
|
2019-02-05 21:30:48 -08:00
|
|
|
exp := balanceTokens.Sub(valTokens).Add(initial.DivRaw(2))
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.Coins{{sdk.DefaultBondDenom, exp}}, ak.GetAccount(ctx, sdk.AccAddress(valOpAddr1)).GetCoins())
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// withdraw commission
|
|
|
|
require.Nil(t, k.WithdrawValidatorCommission(ctx, valOpAddr1))
|
|
|
|
|
|
|
|
// assert correct balance
|
2019-02-05 21:30:48 -08:00
|
|
|
exp = balanceTokens.Sub(valTokens).Add(initial)
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.Coins{{sdk.DefaultBondDenom, exp}}, ak.GetAccount(ctx, sdk.AccAddress(valOpAddr1)).GetCoins())
|
2019-01-16 13:38:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) {
|
|
|
|
ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000)
|
|
|
|
sh := staking.NewHandler(sk)
|
|
|
|
|
|
|
|
// initialize state
|
|
|
|
k.SetOutstandingRewards(ctx, sdk.DecCoins{})
|
|
|
|
|
|
|
|
// create validator with 50% commission
|
2019-02-05 21:30:48 -08:00
|
|
|
power := int64(100)
|
2019-02-13 15:01:50 -08:00
|
|
|
valTokens := sdk.TokensFromTendermintPower(power)
|
2019-01-16 13:38:05 -08:00
|
|
|
commission := staking.NewCommissionMsg(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
|
|
|
|
msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1,
|
2019-02-13 15:01:50 -08:00
|
|
|
sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt())
|
2019-01-16 13:38:05 -08:00
|
|
|
require.True(t, sh(ctx, msg).IsOK())
|
|
|
|
|
|
|
|
// end block to bond validator
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// fetch validator and delegation
|
|
|
|
val := sk.Validator(ctx, valOpAddr1)
|
|
|
|
del := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod := k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards
|
|
|
|
rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
|
|
|
|
|
|
|
// rewards should be zero
|
|
|
|
require.True(t, rewards.IsZero())
|
|
|
|
|
|
|
|
// start out block height
|
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
|
|
|
|
|
|
|
// allocate some rewards
|
2019-02-13 15:01:50 -08:00
|
|
|
initial := sdk.NewDecFromInt(sdk.TokensFromTendermintPower(10))
|
|
|
|
tokens := sdk.DecCoins{{sdk.DefaultBondDenom, initial}}
|
2019-01-16 13:38:05 -08:00
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// slash the validator by 50%
|
2019-02-05 21:30:48 -08:00
|
|
|
sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1))
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// slash the validator by 50% again
|
2019-02-05 21:30:48 -08:00
|
|
|
sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power/2, sdk.NewDecWithPrec(5, 1))
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// fetch the validator again
|
|
|
|
val = sk.Validator(ctx, valOpAddr1)
|
|
|
|
|
|
|
|
// increase block height
|
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
|
|
|
|
|
|
|
// allocate some more rewards
|
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod = k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
|
|
|
|
|
|
|
// rewards should be half the tokens
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, initial}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// commission should be the other half
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, initial}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1))
|
2019-01-16 13:38:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) {
|
|
|
|
ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000)
|
|
|
|
sh := staking.NewHandler(sk)
|
|
|
|
|
|
|
|
// initialize state
|
|
|
|
k.SetOutstandingRewards(ctx, sdk.DecCoins{})
|
|
|
|
|
|
|
|
// create validator with 50% commission
|
|
|
|
commission := staking.NewCommissionMsg(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
|
2019-02-05 21:30:48 -08:00
|
|
|
power := int64(100)
|
2019-02-13 15:01:50 -08:00
|
|
|
valTokens := sdk.TokensFromTendermintPower(power)
|
2019-01-16 13:38:05 -08:00
|
|
|
msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1,
|
2019-02-13 15:01:50 -08:00
|
|
|
sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt())
|
2019-01-16 13:38:05 -08:00
|
|
|
require.True(t, sh(ctx, msg).IsOK())
|
|
|
|
|
|
|
|
// end block to bond validator
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// fetch validator and delegation
|
|
|
|
val := sk.Validator(ctx, valOpAddr1)
|
|
|
|
del1 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
|
|
|
|
|
|
|
// allocate some rewards
|
2019-02-13 15:01:50 -08:00
|
|
|
initial := sdk.NewDecFromInt(sdk.TokensFromTendermintPower(30))
|
|
|
|
tokens := sdk.DecCoins{{sdk.DefaultBondDenom, initial}}
|
2019-01-16 13:38:05 -08:00
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// slash the validator
|
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
2019-02-05 21:30:48 -08:00
|
|
|
sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1))
|
2019-01-16 13:38:05 -08:00
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
|
|
|
|
|
|
|
// second delegation
|
2019-02-13 15:01:50 -08:00
|
|
|
delTokens := sdk.TokensFromTendermintPower(100)
|
2019-02-05 21:30:48 -08:00
|
|
|
msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1,
|
2019-02-13 15:01:50 -08:00
|
|
|
sdk.NewCoin(sdk.DefaultBondDenom, delTokens))
|
2019-01-16 13:38:05 -08:00
|
|
|
require.True(t, sh(ctx, msg2).IsOK())
|
|
|
|
del2 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1)
|
|
|
|
|
|
|
|
// end block
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// allocate some more rewards
|
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// slash the validator again
|
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
2019-02-05 21:30:48 -08:00
|
|
|
sk.Slash(ctx, valConsAddr1, ctx.BlockHeight(), power, sdk.NewDecWithPrec(5, 1))
|
2019-01-16 13:38:05 -08:00
|
|
|
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3)
|
|
|
|
|
|
|
|
// fetch updated validator
|
|
|
|
val = sk.Validator(ctx, valOpAddr1)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod := k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards for del1
|
|
|
|
rewards := k.calculateDelegationRewards(ctx, val, del1, endingPeriod)
|
|
|
|
|
|
|
|
// rewards for del1 should be 2/3 initial (half initial first period, 1/6 initial second period)
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, initial.QuoInt64(2).Add(initial.QuoInt64(6))}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// calculate delegation rewards for del2
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del2, endingPeriod)
|
|
|
|
|
|
|
|
// rewards for del2 should be initial / 3
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, initial.QuoInt64(3)}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// commission should be equal to initial (twice 50% commission, unaffected by slashing)
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, initial}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1))
|
2019-01-16 13:38:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) {
|
|
|
|
ctx, _, k, sk, _ := CreateTestInputDefault(t, false, 1000)
|
|
|
|
sh := staking.NewHandler(sk)
|
|
|
|
|
|
|
|
// initialize state
|
|
|
|
k.SetOutstandingRewards(ctx, sdk.DecCoins{})
|
|
|
|
|
|
|
|
// create validator with 50% commission
|
|
|
|
commission := staking.NewCommissionMsg(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0))
|
|
|
|
msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1,
|
2019-02-13 15:01:50 -08:00
|
|
|
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt())
|
2019-01-16 13:38:05 -08:00
|
|
|
require.True(t, sh(ctx, msg).IsOK())
|
|
|
|
|
|
|
|
// end block to bond validator
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// fetch validator and delegation
|
|
|
|
val := sk.Validator(ctx, valOpAddr1)
|
|
|
|
del1 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
|
|
|
|
|
|
|
// allocate some rewards
|
|
|
|
initial := int64(20)
|
2019-02-13 15:01:50 -08:00
|
|
|
tokens := sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial)}}
|
2019-01-16 13:38:05 -08:00
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
2019-01-23 03:37:03 -08:00
|
|
|
// historical count should be 2 (validator init, delegation init)
|
2019-01-24 13:01:32 -08:00
|
|
|
require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx))
|
2019-01-23 03:37:03 -08:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// second delegation
|
2019-02-13 15:01:50 -08:00
|
|
|
msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)))
|
2019-01-16 13:38:05 -08:00
|
|
|
require.True(t, sh(ctx, msg2).IsOK())
|
|
|
|
|
2019-01-23 03:37:03 -08:00
|
|
|
// historical count should be 3 (second delegation init)
|
2019-01-24 13:01:32 -08:00
|
|
|
require.Equal(t, uint64(3), k.GetValidatorHistoricalReferenceCount(ctx))
|
2019-01-23 03:37:03 -08:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// fetch updated validator
|
|
|
|
val = sk.Validator(ctx, valOpAddr1)
|
|
|
|
del2 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1)
|
|
|
|
|
|
|
|
// end block
|
|
|
|
staking.EndBlocker(ctx, sk)
|
|
|
|
|
|
|
|
// allocate some more rewards
|
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// first delegator withdraws
|
|
|
|
k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
|
|
|
|
|
|
|
// second delegator withdraws
|
|
|
|
k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1)
|
|
|
|
|
2019-01-23 03:37:03 -08:00
|
|
|
// historical count should be 3 (validator init + two delegations)
|
2019-01-24 13:01:32 -08:00
|
|
|
require.Equal(t, uint64(3), k.GetValidatorHistoricalReferenceCount(ctx))
|
2019-01-23 03:37:03 -08:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// validator withdraws commission
|
|
|
|
k.WithdrawValidatorCommission(ctx, valOpAddr1)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod := k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards for del1
|
|
|
|
rewards := k.calculateDelegationRewards(ctx, val, del1, endingPeriod)
|
|
|
|
|
|
|
|
// rewards for del1 should be zero
|
|
|
|
require.True(t, rewards.IsZero())
|
|
|
|
|
|
|
|
// calculate delegation rewards for del2
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del2, endingPeriod)
|
|
|
|
|
|
|
|
// rewards for del2 should be zero
|
|
|
|
require.True(t, rewards.IsZero())
|
|
|
|
|
|
|
|
// commission should be zero
|
|
|
|
require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).IsZero())
|
|
|
|
|
|
|
|
// allocate some more rewards
|
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// first delegator withdraws again
|
|
|
|
k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod = k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards for del1
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del1, endingPeriod)
|
|
|
|
|
|
|
|
// rewards for del1 should be zero
|
|
|
|
require.True(t, rewards.IsZero())
|
|
|
|
|
|
|
|
// calculate delegation rewards for del2
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del2, endingPeriod)
|
|
|
|
|
|
|
|
// rewards for del2 should be 1/4 initial
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial / 4)}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// commission should be half initial
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial / 2)}}, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1))
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// allocate some more rewards
|
|
|
|
k.AllocateTokensToValidator(ctx, val, tokens)
|
|
|
|
|
|
|
|
// withdraw commission
|
|
|
|
k.WithdrawValidatorCommission(ctx, valOpAddr1)
|
|
|
|
|
|
|
|
// end period
|
|
|
|
endingPeriod = k.incrementValidatorPeriod(ctx, val)
|
|
|
|
|
|
|
|
// calculate delegation rewards for del1
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del1, endingPeriod)
|
|
|
|
|
|
|
|
// rewards for del1 should be 1/4 initial
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial / 4)}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// calculate delegation rewards for del2
|
|
|
|
rewards = k.calculateDelegationRewards(ctx, val, del2, endingPeriod)
|
|
|
|
|
|
|
|
// rewards for del2 should be 1/2 initial
|
2019-02-13 15:01:50 -08:00
|
|
|
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial / 2)}}, rewards)
|
2019-01-16 13:38:05 -08:00
|
|
|
|
|
|
|
// commission should be zero
|
|
|
|
require.True(t, k.GetValidatorAccumulatedCommission(ctx, valOpAddr1).IsZero())
|
2018-10-04 18:37:40 -07:00
|
|
|
}
|