249 lines
9.8 KiB
Go
249 lines
9.8 KiB
Go
package keeper_test
|
||
|
||
import (
|
||
"testing"
|
||
|
||
"cosmossdk.io/math"
|
||
"github.com/stretchr/testify/require"
|
||
abci "github.com/tendermint/tendermint/abci/types"
|
||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||
|
||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
||
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil"
|
||
"github.com/cosmos/cosmos-sdk/x/distribution/keeper"
|
||
"github.com/cosmos/cosmos-sdk/x/distribution/testutil"
|
||
disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
|
||
stakingtestutil "github.com/cosmos/cosmos-sdk/x/staking/testutil"
|
||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||
)
|
||
|
||
func TestAllocateTokensToValidatorWithCommission(t *testing.T) {
|
||
var (
|
||
bankKeeper bankkeeper.Keeper
|
||
distrKeeper keeper.Keeper
|
||
stakingKeeper *stakingkeeper.Keeper
|
||
)
|
||
|
||
app, err := simtestutil.Setup(testutil.AppConfig,
|
||
&bankKeeper,
|
||
&distrKeeper,
|
||
&stakingKeeper,
|
||
)
|
||
require.NoError(t, err)
|
||
|
||
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
|
||
|
||
addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 3, sdk.NewInt(1234))
|
||
valAddrs := simtestutil.ConvertAddrsToValAddrs(addrs)
|
||
tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper)
|
||
|
||
// create validator with 50% commission
|
||
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0))
|
||
tstaking.CreateValidator(sdk.ValAddress(addrs[0]), valConsPk0, sdk.NewInt(100), true)
|
||
val := stakingKeeper.Validator(ctx, valAddrs[0])
|
||
|
||
// allocate tokens
|
||
tokens := sdk.DecCoins{
|
||
{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(10)},
|
||
}
|
||
distrKeeper.AllocateTokensToValidator(ctx, val, tokens)
|
||
|
||
// check commission
|
||
expected := sdk.DecCoins{
|
||
{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(5)},
|
||
}
|
||
require.Equal(t, expected, distrKeeper.GetValidatorAccumulatedCommission(ctx, val.GetOperator()).Commission)
|
||
|
||
// check current rewards
|
||
require.Equal(t, expected, distrKeeper.GetValidatorCurrentRewards(ctx, val.GetOperator()).Rewards)
|
||
}
|
||
|
||
func TestAllocateTokensToManyValidators(t *testing.T) {
|
||
var (
|
||
accountKeeper authkeeper.AccountKeeper
|
||
bankKeeper bankkeeper.Keeper
|
||
distrKeeper keeper.Keeper
|
||
stakingKeeper *stakingkeeper.Keeper
|
||
)
|
||
|
||
app, err := simtestutil.Setup(testutil.AppConfig,
|
||
&accountKeeper,
|
||
&bankKeeper,
|
||
&distrKeeper,
|
||
&stakingKeeper,
|
||
)
|
||
require.NoError(t, err)
|
||
|
||
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
|
||
|
||
// reset fee pool
|
||
distrKeeper.SetFeePool(ctx, disttypes.InitialFeePool())
|
||
|
||
addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(1234))
|
||
valAddrs := simtestutil.ConvertAddrsToValAddrs(addrs)
|
||
tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper)
|
||
|
||
// create validator with 50% commission
|
||
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0))
|
||
tstaking.CreateValidator(valAddrs[0], valConsPk0, sdk.NewInt(100), true)
|
||
|
||
// create second validator with 0% commission
|
||
tstaking.Commission = stakingtypes.NewCommissionRates(math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0))
|
||
tstaking.CreateValidator(valAddrs[1], valConsPk1, sdk.NewInt(100), true)
|
||
|
||
abciValA := abci.Validator{
|
||
Address: valConsPk0.Address(),
|
||
Power: 100,
|
||
}
|
||
abciValB := abci.Validator{
|
||
Address: valConsPk1.Address(),
|
||
Power: 100,
|
||
}
|
||
|
||
// assert initial state: zero outstanding rewards, zero community pool, zero commission, zero current rewards
|
||
require.True(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero())
|
||
require.True(t, distrKeeper.GetFeePool(ctx).CommunityPool.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards.IsZero())
|
||
|
||
// allocate tokens as if both had voted and second was proposer
|
||
fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)))
|
||
feeCollector := accountKeeper.GetModuleAccount(ctx, types.FeeCollectorName)
|
||
require.NotNil(t, feeCollector)
|
||
|
||
// fund fee collector
|
||
require.NoError(t, banktestutil.FundModuleAccount(bankKeeper, ctx, feeCollector.GetName(), fees))
|
||
|
||
accountKeeper.SetAccount(ctx, feeCollector)
|
||
|
||
votes := []abci.VoteInfo{
|
||
{
|
||
Validator: abciValA,
|
||
SignedLastBlock: true,
|
||
},
|
||
{
|
||
Validator: abciValB,
|
||
SignedLastBlock: true,
|
||
},
|
||
}
|
||
distrKeeper.AllocateTokens(ctx, 200, votes)
|
||
|
||
// 98 outstanding rewards (100 less 2 to community pool)
|
||
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(490, 1)}}, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards)
|
||
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(490, 1)}}, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards)
|
||
|
||
// 2 community pool coins
|
||
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(2)}}, distrKeeper.GetFeePool(ctx).CommunityPool)
|
||
|
||
// 50% commission for first proposer, (0.5 * 98%) * 100 / 2 = 23.25
|
||
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2450, 2)}}, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission)
|
||
|
||
// zero commission for second proposer
|
||
require.True(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero())
|
||
|
||
// just staking.proportional for first proposer less commission = (0.5 * 98%) * 100 / 2 = 24.50
|
||
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2450, 2)}}, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards)
|
||
|
||
// proposer reward + staking.proportional for second proposer = (0.5 * (98%)) * 100 = 49
|
||
require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(490, 1)}}, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards)
|
||
}
|
||
|
||
func TestAllocateTokensTruncation(t *testing.T) {
|
||
var (
|
||
accountKeeper authkeeper.AccountKeeper
|
||
bankKeeper bankkeeper.Keeper
|
||
distrKeeper keeper.Keeper
|
||
stakingKeeper *stakingkeeper.Keeper
|
||
)
|
||
|
||
app, err := simtestutil.Setup(testutil.AppConfig,
|
||
&accountKeeper,
|
||
&bankKeeper,
|
||
&distrKeeper,
|
||
&stakingKeeper,
|
||
)
|
||
require.NoError(t, err)
|
||
|
||
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
|
||
|
||
// reset fee pool
|
||
distrKeeper.SetFeePool(ctx, disttypes.InitialFeePool())
|
||
|
||
addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 3, sdk.NewInt(1234))
|
||
valAddrs := simtestutil.ConvertAddrsToValAddrs(addrs)
|
||
tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper)
|
||
|
||
// create validator with 10% commission
|
||
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), math.LegacyNewDec(0))
|
||
tstaking.CreateValidator(valAddrs[0], valConsPk0, sdk.NewInt(110), true)
|
||
|
||
// create second validator with 10% commission
|
||
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), math.LegacyNewDec(0))
|
||
tstaking.CreateValidator(valAddrs[1], valConsPk1, sdk.NewInt(100), true)
|
||
|
||
// create third validator with 10% commission
|
||
tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), math.LegacyNewDec(0))
|
||
tstaking.CreateValidator(valAddrs[2], valConsPk2, sdk.NewInt(100), true)
|
||
|
||
abciValA := abci.Validator{
|
||
Address: valConsPk0.Address(),
|
||
Power: 11,
|
||
}
|
||
abciValB := abci.Validator{
|
||
Address: valConsPk1.Address(),
|
||
Power: 10,
|
||
}
|
||
abciValС := abci.Validator{
|
||
Address: valConsPk2.Address(),
|
||
Power: 10,
|
||
}
|
||
|
||
// assert initial state: zero outstanding rewards, zero community pool, zero commission, zero current rewards
|
||
require.True(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero())
|
||
require.True(t, distrKeeper.GetFeePool(ctx).CommunityPool.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards.IsZero())
|
||
require.True(t, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards.IsZero())
|
||
|
||
// allocate tokens as if both had voted and second was proposer
|
||
fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(634195840)))
|
||
|
||
feeCollector := accountKeeper.GetModuleAccount(ctx, types.FeeCollectorName)
|
||
require.NotNil(t, feeCollector)
|
||
|
||
require.NoError(t, banktestutil.FundModuleAccount(bankKeeper, ctx, feeCollector.GetName(), fees))
|
||
|
||
accountKeeper.SetAccount(ctx, feeCollector)
|
||
|
||
votes := []abci.VoteInfo{
|
||
{
|
||
Validator: abciValA,
|
||
SignedLastBlock: true,
|
||
},
|
||
{
|
||
Validator: abciValB,
|
||
SignedLastBlock: true,
|
||
},
|
||
{
|
||
Validator: abciValС,
|
||
SignedLastBlock: true,
|
||
},
|
||
}
|
||
distrKeeper.AllocateTokens(ctx, 31, votes)
|
||
|
||
require.True(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsValid())
|
||
require.True(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsValid())
|
||
require.True(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[2]).Rewards.IsValid())
|
||
}
|