test(integration): port x/slashing tests to server v2 (#22754)
This commit is contained in:
parent
66c593f147
commit
00c7756610
@ -1,32 +0,0 @@
|
||||
package slashing
|
||||
|
||||
import (
|
||||
_ "cosmossdk.io/x/accounts" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/bank" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/consensus" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/distribution" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/mint" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/protocolpool" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/slashing" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/staking" // import as blank for app wiring
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil/configurator"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/auth" // import as blank for app wiring
|
||||
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import as blank for app wiring
|
||||
_ "github.com/cosmos/cosmos-sdk/x/genutil" // import as blank for app wiring
|
||||
)
|
||||
|
||||
var AppConfig = configurator.NewAppConfig(
|
||||
configurator.AccountsModule(),
|
||||
configurator.AuthModule(),
|
||||
configurator.BankModule(),
|
||||
configurator.StakingModule(),
|
||||
configurator.SlashingModule(),
|
||||
configurator.TxModule(),
|
||||
configurator.ValidateModule(),
|
||||
configurator.ConsensusModule(),
|
||||
configurator.GenutilModule(),
|
||||
configurator.MintModule(),
|
||||
configurator.DistributionModule(),
|
||||
configurator.ProtocolPoolModule(),
|
||||
)
|
||||
@ -1,119 +0,0 @@
|
||||
package slashing_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/math"
|
||||
bankkeeper "cosmossdk.io/x/bank/keeper"
|
||||
"cosmossdk.io/x/slashing/keeper"
|
||||
"cosmossdk.io/x/slashing/types"
|
||||
stakingkeeper "cosmossdk.io/x/staking/keeper"
|
||||
stakingtypes "cosmossdk.io/x/staking/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
codecaddress "github.com/cosmos/cosmos-sdk/codec/address"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/configurator"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
var (
|
||||
priv1 = secp256k1.GenPrivKey()
|
||||
addr1 = sdk.AccAddress(priv1.PubKey().Address())
|
||||
addrCodec = codecaddress.NewBech32Codec("cosmos")
|
||||
valaddrCodec = codecaddress.NewBech32Codec("cosmosvaloper")
|
||||
|
||||
valKey = ed25519.GenPrivKey()
|
||||
valAddr = sdk.AccAddress(valKey.PubKey().Address())
|
||||
)
|
||||
|
||||
func TestSlashingMsgs(t *testing.T) {
|
||||
genTokens := sdk.TokensFromConsensusPower(42, sdk.DefaultPowerReduction)
|
||||
bondTokens := sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction)
|
||||
genCoin := sdk.NewCoin(sdk.DefaultBondDenom, genTokens)
|
||||
bondCoin := sdk.NewCoin(sdk.DefaultBondDenom, bondTokens)
|
||||
|
||||
addrStr, err := addrCodec.BytesToString(addr1)
|
||||
require.NoError(t, err)
|
||||
acc1 := &authtypes.BaseAccount{
|
||||
Address: addrStr,
|
||||
}
|
||||
accs := []sims.GenesisAccount{{GenesisAccount: acc1, Coins: sdk.Coins{genCoin}}}
|
||||
|
||||
startupCfg := sims.DefaultStartUpConfig()
|
||||
startupCfg.GenesisAccounts = accs
|
||||
|
||||
var (
|
||||
stakingKeeper *stakingkeeper.Keeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
slashingKeeper keeper.Keeper
|
||||
txConfig client.TxConfig
|
||||
)
|
||||
|
||||
app, err := sims.SetupWithConfiguration(
|
||||
depinject.Configs(
|
||||
configurator.NewAppConfig(
|
||||
configurator.AccountsModule(),
|
||||
configurator.AuthModule(),
|
||||
configurator.StakingModule(),
|
||||
configurator.SlashingModule(),
|
||||
configurator.TxModule(),
|
||||
configurator.ValidateModule(),
|
||||
configurator.ConsensusModule(),
|
||||
configurator.BankModule(),
|
||||
),
|
||||
depinject.Supply(log.NewNopLogger()),
|
||||
),
|
||||
startupCfg, &stakingKeeper, &bankKeeper, &slashingKeeper, &txConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
baseApp := app.BaseApp
|
||||
|
||||
ctxCheck := baseApp.NewContext(true)
|
||||
require.True(t, sdk.Coins{genCoin}.Equal(bankKeeper.GetAllBalances(ctxCheck, addr1)))
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
description := stakingtypes.NewDescription("foo_moniker", "", "", "", "", &stakingtypes.Metadata{})
|
||||
commission := stakingtypes.NewCommissionRates(math.LegacyZeroDec(), math.LegacyZeroDec(), math.LegacyZeroDec())
|
||||
|
||||
addrStrVal, err := valaddrCodec.BytesToString(addr1)
|
||||
require.NoError(t, err)
|
||||
createValidatorMsg, err := stakingtypes.NewMsgCreateValidator(
|
||||
addrStrVal, valKey.PubKey(), bondCoin, description, commission, math.OneInt(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
headerInfo := header.Info{Height: app.LastBlockHeight() + 1}
|
||||
_, _, err = sims.SignCheckDeliver(t, txConfig, app.BaseApp, headerInfo, []sdk.Msg{createValidatorMsg}, "", []uint64{0}, []uint64{0}, true, true, priv1)
|
||||
require.NoError(t, err)
|
||||
require.True(t, sdk.Coins{genCoin.Sub(bondCoin)}.Equal(bankKeeper.GetAllBalances(ctxCheck, addr1)))
|
||||
|
||||
ctxCheck = baseApp.NewContext(true)
|
||||
validator, err := stakingKeeper.GetValidator(ctxCheck, sdk.ValAddress(addr1))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, addrStrVal, validator.OperatorAddress)
|
||||
require.Equal(t, stakingtypes.Bonded, validator.Status)
|
||||
require.True(math.IntEq(t, bondTokens, validator.BondedTokens()))
|
||||
unjailMsg := &types.MsgUnjail{ValidatorAddr: addrStrVal}
|
||||
|
||||
ctxCheck = app.BaseApp.NewContext(true)
|
||||
_, err = slashingKeeper.ValidatorSigningInfo.Get(ctxCheck, sdk.ConsAddress(valAddr))
|
||||
require.NoError(t, err)
|
||||
|
||||
// unjail should fail with unknown validator
|
||||
headerInfo = header.Info{Height: app.LastBlockHeight() + 1}
|
||||
_, _, err = sims.SignCheckDeliver(t, txConfig, app.BaseApp, headerInfo, []sdk.Msg{unjailMsg}, "", []uint64{0}, []uint64{1}, false, false, priv1)
|
||||
require.Error(t, err)
|
||||
require.True(t, errors.Is(err, types.ErrValidatorNotJailed))
|
||||
}
|
||||
@ -8,68 +8,43 @@ import (
|
||||
|
||||
"cosmossdk.io/core/comet"
|
||||
coreheader "cosmossdk.io/core/header"
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/log"
|
||||
bankkeeper "cosmossdk.io/x/bank/keeper"
|
||||
"cosmossdk.io/runtime/v2/services"
|
||||
"cosmossdk.io/x/slashing"
|
||||
slashingkeeper "cosmossdk.io/x/slashing/keeper"
|
||||
"cosmossdk.io/x/slashing/testutil"
|
||||
stakingkeeper "cosmossdk.io/x/staking/keeper"
|
||||
stakingtestutil "cosmossdk.io/x/staking/testutil"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
"github.com/cosmos/cosmos-sdk/tests/integration/v2"
|
||||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
)
|
||||
|
||||
// TestBeginBlocker is a unit test function that tests the behavior of the BeginBlocker function.
|
||||
// It sets up the necessary dependencies and context, creates a validator, and performs various operations
|
||||
// to test the slashing logic. It checks if the validator is correctly jailed after a certain number of blocks.
|
||||
func TestBeginBlocker(t *testing.T) {
|
||||
var (
|
||||
interfaceRegistry codectypes.InterfaceRegistry
|
||||
accountKeeper authkeeper.AccountKeeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
stakingKeeper *stakingkeeper.Keeper
|
||||
slashingKeeper slashingkeeper.Keeper
|
||||
)
|
||||
f := initFixture(t)
|
||||
|
||||
app, err := simtestutil.Setup(
|
||||
depinject.Configs(
|
||||
AppConfig,
|
||||
depinject.Supply(log.NewNopLogger()),
|
||||
),
|
||||
&interfaceRegistry,
|
||||
&accountKeeper,
|
||||
&bankKeeper,
|
||||
&stakingKeeper,
|
||||
&slashingKeeper,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := app.BaseApp.NewContext(false)
|
||||
ctx := f.ctx
|
||||
|
||||
pks := simtestutil.CreateTestPubKeys(1)
|
||||
simtestutil.AddTestAddrsFromPubKeys(bankKeeper, stakingKeeper, ctx, pks, stakingKeeper.TokensFromConsensusPower(ctx, 200))
|
||||
simtestutil.AddTestAddrsFromPubKeys(f.bankKeeper, f.stakingKeeper, ctx, pks, f.stakingKeeper.TokensFromConsensusPower(ctx, 200))
|
||||
addr, pk := sdk.ValAddress(pks[0].Address()), pks[0]
|
||||
tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper)
|
||||
tstaking := stakingtestutil.NewHelper(t, ctx, f.stakingKeeper)
|
||||
|
||||
// bond the validator
|
||||
power := int64(100)
|
||||
acc := accountKeeper.NewAccountWithAddress(ctx, sdk.AccAddress(addr))
|
||||
accountKeeper.SetAccount(ctx, acc)
|
||||
acc := f.accountKeeper.NewAccountWithAddress(ctx, sdk.AccAddress(addr))
|
||||
f.accountKeeper.SetAccount(ctx, acc)
|
||||
amt := tstaking.CreateValidatorWithValPower(addr, pk, power, true)
|
||||
_, err = stakingKeeper.EndBlocker(ctx)
|
||||
_, err := f.stakingKeeper.EndBlocker(ctx)
|
||||
require.NoError(t, err)
|
||||
bondDenom, err := stakingKeeper.BondDenom(ctx)
|
||||
bondDenom, err := f.stakingKeeper.BondDenom(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(
|
||||
t, bankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)),
|
||||
t, f.bankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)),
|
||||
sdk.NewCoins(sdk.NewCoin(bondDenom, testutil.InitTokens.Sub(amt))),
|
||||
)
|
||||
val, err := stakingKeeper.Validator(ctx, addr)
|
||||
val, err := f.stakingKeeper.Validator(ctx, addr)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, amt, val.GetBondedTokens())
|
||||
|
||||
@ -78,57 +53,58 @@ func TestBeginBlocker(t *testing.T) {
|
||||
Power: power,
|
||||
}
|
||||
|
||||
ctx = ctx.WithCometInfo(comet.Info{
|
||||
ctx = integration.SetCometInfo(ctx, comet.Info{
|
||||
LastCommit: comet.CommitInfo{Votes: []comet.VoteInfo{{
|
||||
Validator: abciVal,
|
||||
BlockIDFlag: comet.BlockIDFlagCommit,
|
||||
}}},
|
||||
})
|
||||
cometInfoService := runtime.NewContextAwareCometInfoService()
|
||||
cometInfoService := &services.ContextAwareCometInfoService{}
|
||||
|
||||
err = slashing.BeginBlocker(ctx, slashingKeeper, cometInfoService)
|
||||
err = slashing.BeginBlocker(ctx, f.slashingKeeper, cometInfoService)
|
||||
require.NoError(t, err)
|
||||
|
||||
info, err := slashingKeeper.ValidatorSigningInfo.Get(ctx, sdk.ConsAddress(pk.Address()))
|
||||
info, err := f.slashingKeeper.ValidatorSigningInfo.Get(ctx, sdk.ConsAddress(pk.Address()))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ctx.HeaderInfo().Height, info.StartHeight)
|
||||
require.Equal(t, integration.HeaderInfoFromContext(ctx).Height, info.StartHeight)
|
||||
require.Equal(t, int64(0), info.IndexOffset)
|
||||
require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil)
|
||||
require.Equal(t, int64(0), info.MissedBlocksCounter)
|
||||
|
||||
height := int64(0)
|
||||
|
||||
signedBlocksWindow, err := slashingKeeper.SignedBlocksWindow(ctx)
|
||||
signedBlocksWindow, err := f.slashingKeeper.SignedBlocksWindow(ctx)
|
||||
require.NoError(t, err)
|
||||
// for 100 blocks, mark the validator as having signed
|
||||
for ; height < signedBlocksWindow; height++ {
|
||||
ctx = ctx.WithHeaderInfo(coreheader.Info{Height: height})
|
||||
ctx = integration.SetHeaderInfo(ctx, coreheader.Info{Height: height})
|
||||
|
||||
err = slashing.BeginBlocker(ctx, slashingKeeper, cometInfoService)
|
||||
err = slashing.BeginBlocker(ctx, f.slashingKeeper, cometInfoService)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
minSignedPerWindow, err := slashingKeeper.MinSignedPerWindow(ctx)
|
||||
minSignedPerWindow, err := f.slashingKeeper.MinSignedPerWindow(ctx)
|
||||
require.NoError(t, err)
|
||||
// for 50 blocks, mark the validator as having not signed
|
||||
for ; height < ((signedBlocksWindow * 2) - minSignedPerWindow + 1); height++ {
|
||||
ctx = ctx.WithHeaderInfo(coreheader.Info{Height: height}).WithCometInfo(comet.Info{
|
||||
ctx = integration.SetHeaderInfo(ctx, coreheader.Info{Height: height})
|
||||
ctx = integration.SetCometInfo(ctx, comet.Info{
|
||||
LastCommit: comet.CommitInfo{Votes: []comet.VoteInfo{{
|
||||
Validator: abciVal,
|
||||
BlockIDFlag: comet.BlockIDFlagAbsent,
|
||||
}}},
|
||||
})
|
||||
|
||||
err = slashing.BeginBlocker(ctx, slashingKeeper, cometInfoService)
|
||||
err = slashing.BeginBlocker(ctx, f.slashingKeeper, cometInfoService)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// end block
|
||||
_, err = stakingKeeper.EndBlocker(ctx)
|
||||
_, err = f.stakingKeeper.EndBlocker(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// validator should be jailed
|
||||
validator, err := stakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(pk))
|
||||
validator, err := f.stakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(pk))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package keeper_test
|
||||
package slashing
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -6,173 +6,21 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"cosmossdk.io/core/appmodule"
|
||||
"cosmossdk.io/core/comet"
|
||||
coreheader "cosmossdk.io/core/header"
|
||||
"cosmossdk.io/log"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
"cosmossdk.io/x/bank"
|
||||
bankkeeper "cosmossdk.io/x/bank/keeper"
|
||||
banktypes "cosmossdk.io/x/bank/types"
|
||||
"cosmossdk.io/x/consensus"
|
||||
consensusparamkeeper "cosmossdk.io/x/consensus/keeper"
|
||||
consensustypes "cosmossdk.io/x/consensus/types"
|
||||
minttypes "cosmossdk.io/x/mint/types"
|
||||
"cosmossdk.io/x/slashing"
|
||||
slashingkeeper "cosmossdk.io/x/slashing/keeper"
|
||||
"cosmossdk.io/core/transaction"
|
||||
"cosmossdk.io/x/slashing/testutil"
|
||||
slashingtypes "cosmossdk.io/x/slashing/types"
|
||||
"cosmossdk.io/x/staking"
|
||||
stakingkeeper "cosmossdk.io/x/staking/keeper"
|
||||
stakingtestutil "cosmossdk.io/x/staking/testutil"
|
||||
stakingtypes "cosmossdk.io/x/staking/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
|
||||
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/integration"
|
||||
"github.com/cosmos/cosmos-sdk/tests/integration/v2"
|
||||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
type fixture struct {
|
||||
app *integration.App
|
||||
|
||||
ctx sdk.Context
|
||||
|
||||
accountKeeper authkeeper.AccountKeeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
slashingKeeper slashingkeeper.Keeper
|
||||
stakingKeeper *stakingkeeper.Keeper
|
||||
|
||||
addrDels []sdk.AccAddress
|
||||
valAddrs []sdk.ValAddress
|
||||
}
|
||||
|
||||
func initFixture(tb testing.TB) *fixture {
|
||||
tb.Helper()
|
||||
keys := storetypes.NewKVStoreKeys(
|
||||
authtypes.StoreKey, banktypes.StoreKey, slashingtypes.StoreKey, stakingtypes.StoreKey, consensustypes.StoreKey,
|
||||
)
|
||||
encodingCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, auth.AppModule{})
|
||||
cdc := encodingCfg.Codec
|
||||
|
||||
authority := authtypes.NewModuleAddress("gov")
|
||||
|
||||
maccPerms := map[string][]string{
|
||||
minttypes.ModuleName: {authtypes.Minter},
|
||||
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||
}
|
||||
|
||||
msgRouter := baseapp.NewMsgServiceRouter()
|
||||
queryRouter := baseapp.NewGRPCQueryRouter()
|
||||
|
||||
// gomock initializations
|
||||
ctrl := gomock.NewController(tb)
|
||||
acctsModKeeper := authtestutil.NewMockAccountsModKeeper(ctrl)
|
||||
accNum := uint64(0)
|
||||
acctsModKeeper.EXPECT().NextAccountNumber(gomock.Any()).AnyTimes().DoAndReturn(func(ctx context.Context) (uint64, error) {
|
||||
currentNum := accNum
|
||||
accNum++
|
||||
return currentNum, nil
|
||||
})
|
||||
|
||||
accountKeeper := authkeeper.NewAccountKeeper(
|
||||
runtime.NewEnvironment(runtime.NewKVStoreService(keys[authtypes.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(msgRouter)),
|
||||
cdc,
|
||||
authtypes.ProtoBaseAccount,
|
||||
acctsModKeeper,
|
||||
maccPerms,
|
||||
addresscodec.NewBech32Codec(sdk.Bech32MainPrefix),
|
||||
sdk.Bech32MainPrefix,
|
||||
authority.String(),
|
||||
)
|
||||
|
||||
blockedAddresses := map[string]bool{
|
||||
accountKeeper.GetAuthority(): false,
|
||||
}
|
||||
bankKeeper := bankkeeper.NewBaseKeeper(
|
||||
runtime.NewEnvironment(runtime.NewKVStoreService(keys[banktypes.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(msgRouter)),
|
||||
cdc,
|
||||
accountKeeper,
|
||||
blockedAddresses,
|
||||
authority.String(),
|
||||
)
|
||||
|
||||
cometInfoService := runtime.NewContextAwareCometInfoService()
|
||||
|
||||
consensusParamsKeeper := consensusparamkeeper.NewKeeper(cdc, runtime.NewEnvironment(runtime.NewKVStoreService(keys[consensustypes.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(msgRouter)), authtypes.NewModuleAddress("gov").String())
|
||||
|
||||
stakingKeeper := stakingkeeper.NewKeeper(cdc, runtime.NewEnvironment(runtime.NewKVStoreService(keys[stakingtypes.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(msgRouter)), accountKeeper, bankKeeper, consensusParamsKeeper, authority.String(), addresscodec.NewBech32Codec(sdk.Bech32PrefixValAddr), addresscodec.NewBech32Codec(sdk.Bech32PrefixConsAddr), cometInfoService)
|
||||
|
||||
slashingKeeper := slashingkeeper.NewKeeper(runtime.NewEnvironment(runtime.NewKVStoreService(keys[slashingtypes.StoreKey]), log.NewNopLogger(), runtime.EnvWithQueryRouterService(queryRouter), runtime.EnvWithMsgRouterService(msgRouter)), cdc, &codec.LegacyAmino{}, stakingKeeper, authority.String())
|
||||
|
||||
bankModule := bank.NewAppModule(cdc, bankKeeper, accountKeeper)
|
||||
stakingModule := staking.NewAppModule(cdc, stakingKeeper)
|
||||
slashingModule := slashing.NewAppModule(cdc, slashingKeeper, accountKeeper, bankKeeper, stakingKeeper, cdc.InterfaceRegistry(), cometInfoService)
|
||||
consensusModule := consensus.NewAppModule(cdc, consensusParamsKeeper)
|
||||
|
||||
integrationApp := integration.NewIntegrationApp(log.NewNopLogger(), keys, cdc,
|
||||
encodingCfg.InterfaceRegistry.SigningContext().AddressCodec(),
|
||||
encodingCfg.InterfaceRegistry.SigningContext().ValidatorAddressCodec(),
|
||||
map[string]appmodule.AppModule{
|
||||
banktypes.ModuleName: bankModule,
|
||||
stakingtypes.ModuleName: stakingModule,
|
||||
slashingtypes.ModuleName: slashingModule,
|
||||
consensustypes.ModuleName: consensusModule,
|
||||
},
|
||||
msgRouter,
|
||||
queryRouter,
|
||||
)
|
||||
|
||||
sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context())
|
||||
|
||||
// Register MsgServer and QueryServer
|
||||
slashingtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), slashingkeeper.NewMsgServerImpl(slashingKeeper))
|
||||
slashingtypes.RegisterQueryServer(integrationApp.QueryHelper(), slashingkeeper.NewQuerier(slashingKeeper))
|
||||
|
||||
// set default staking params
|
||||
// TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500
|
||||
err := slashingKeeper.Params.Set(sdkCtx, testutil.TestParams())
|
||||
assert.NilError(tb, err)
|
||||
addrDels := simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, sdkCtx, 6, stakingKeeper.TokensFromConsensusPower(sdkCtx, 200))
|
||||
valAddrs := simtestutil.ConvertAddrsToValAddrs(addrDels)
|
||||
|
||||
consaddr0, err := stakingKeeper.ConsensusAddressCodec().BytesToString(addrDels[0])
|
||||
assert.NilError(tb, err)
|
||||
consaddr1, err := stakingKeeper.ConsensusAddressCodec().BytesToString(addrDels[1])
|
||||
assert.NilError(tb, err)
|
||||
|
||||
info1 := slashingtypes.NewValidatorSigningInfo(consaddr0, int64(4), time.Unix(2, 0), false, int64(10))
|
||||
info2 := slashingtypes.NewValidatorSigningInfo(consaddr1, int64(5), time.Unix(2, 0), false, int64(10))
|
||||
|
||||
err = slashingKeeper.ValidatorSigningInfo.Set(sdkCtx, sdk.ConsAddress(addrDels[0]), info1)
|
||||
assert.NilError(tb, err)
|
||||
err = slashingKeeper.ValidatorSigningInfo.Set(sdkCtx, sdk.ConsAddress(addrDels[1]), info2)
|
||||
assert.NilError(tb, err)
|
||||
return &fixture{
|
||||
app: integrationApp,
|
||||
ctx: sdkCtx,
|
||||
accountKeeper: accountKeeper,
|
||||
bankKeeper: bankKeeper,
|
||||
slashingKeeper: slashingKeeper,
|
||||
stakingKeeper: stakingKeeper,
|
||||
addrDels: addrDels,
|
||||
valAddrs: valAddrs,
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnJailNotBonded(t *testing.T) {
|
||||
t.Parallel()
|
||||
f := initFixture(t)
|
||||
@ -194,8 +42,8 @@ func TestUnJailNotBonded(t *testing.T) {
|
||||
|
||||
_, err = f.stakingKeeper.EndBlocker(f.ctx)
|
||||
assert.NilError(t, err)
|
||||
newHeight := f.ctx.BlockHeight() + 1
|
||||
f.ctx = f.ctx.WithBlockHeight(newHeight).WithHeaderInfo(coreheader.Info{Height: newHeight})
|
||||
newHeight := int64(f.app.LastBlockHeight()) + 1 + 1
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: newHeight})
|
||||
|
||||
// create a 6th validator with less power than the cliff validator (won't be bonded)
|
||||
addr, val := f.valAddrs[5], pks[5]
|
||||
@ -211,8 +59,8 @@ func TestUnJailNotBonded(t *testing.T) {
|
||||
|
||||
_, err = f.stakingKeeper.EndBlocker(f.ctx)
|
||||
assert.NilError(t, err)
|
||||
newHeight = f.ctx.BlockHeight() + 1
|
||||
f.ctx = f.ctx.WithBlockHeight(newHeight).WithHeaderInfo(coreheader.Info{Height: newHeight})
|
||||
newHeight = integration.HeaderInfoFromContext(f.ctx).Height + 1
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: newHeight})
|
||||
|
||||
tstaking.CheckValidator(addr, stakingtypes.Unbonded, false)
|
||||
|
||||
@ -226,8 +74,8 @@ func TestUnJailNotBonded(t *testing.T) {
|
||||
|
||||
_, err = f.stakingKeeper.EndBlocker(f.ctx)
|
||||
assert.NilError(t, err)
|
||||
newHeight = f.ctx.BlockHeight() + 1
|
||||
f.ctx = f.ctx.WithBlockHeight(newHeight).WithHeaderInfo(coreheader.Info{Height: newHeight})
|
||||
newHeight = integration.HeaderInfoFromContext(f.ctx).Height + 1
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: newHeight})
|
||||
|
||||
// verify that validator is jailed
|
||||
tstaking.CheckValidator(addr, -1, true)
|
||||
@ -237,16 +85,20 @@ func TestUnJailNotBonded(t *testing.T) {
|
||||
ValidatorAddr: addr.String(),
|
||||
}
|
||||
_, err = f.app.RunMsg(
|
||||
&msgUnjail,
|
||||
integration.WithAutomaticFinalizeBlock(),
|
||||
t,
|
||||
f.ctx,
|
||||
func(ctx context.Context) (transaction.Msg, error) {
|
||||
res, err := f.slashingMsgServer.Unjail(ctx, &msgUnjail)
|
||||
return res, err
|
||||
},
|
||||
integration.WithAutomaticCommit(),
|
||||
)
|
||||
assert.ErrorContains(t, err, "cannot be unjailed")
|
||||
|
||||
_, err = f.stakingKeeper.EndBlocker(f.ctx)
|
||||
assert.NilError(t, err)
|
||||
newHeight = f.ctx.BlockHeight() + 1
|
||||
f.ctx = f.ctx.WithBlockHeight(newHeight).WithHeaderInfo(coreheader.Info{Height: newHeight})
|
||||
newHeight = integration.HeaderInfoFromContext(f.ctx).Height + 1
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: newHeight})
|
||||
// bond to meet minimum self-delegationa
|
||||
accAddr, err = f.accountKeeper.AddressCodec().BytesToString(addr)
|
||||
assert.NilError(t, err)
|
||||
@ -256,13 +108,17 @@ func TestUnJailNotBonded(t *testing.T) {
|
||||
|
||||
_, err = f.stakingKeeper.EndBlocker(f.ctx)
|
||||
assert.NilError(t, err)
|
||||
newHeight = f.ctx.BlockHeight() + 1
|
||||
f.ctx = f.ctx.WithBlockHeight(newHeight).WithHeaderInfo(coreheader.Info{Height: newHeight})
|
||||
newHeight = integration.HeaderInfoFromContext(f.ctx).Height + 1
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: newHeight})
|
||||
|
||||
// verify we can immediately unjail
|
||||
_, err = f.app.RunMsg(
|
||||
&msgUnjail,
|
||||
integration.WithAutomaticFinalizeBlock(),
|
||||
t,
|
||||
f.ctx,
|
||||
func(ctx context.Context) (transaction.Msg, error) {
|
||||
res, err := f.slashingMsgServer.Unjail(ctx, &msgUnjail)
|
||||
return res, err
|
||||
},
|
||||
integration.WithAutomaticCommit(),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
@ -277,18 +133,25 @@ func TestHandleNewValidator(t *testing.T) {
|
||||
t.Parallel()
|
||||
f := initFixture(t)
|
||||
|
||||
bondDenom, err := f.stakingKeeper.BondDenom(f.ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
bondPool := f.stakingKeeper.GetBondedPool(f.ctx)
|
||||
|
||||
initialBondPoolBal := f.bankKeeper.GetBalance(f.ctx, bondPool.GetAddress(), bondDenom).Amount
|
||||
|
||||
pks := simtestutil.CreateTestPubKeys(1)
|
||||
addr, valpubkey := f.valAddrs[0], pks[0]
|
||||
tstaking := stakingtestutil.NewHelper(t, f.ctx, f.stakingKeeper)
|
||||
signedBlocksWindow, err := f.slashingKeeper.SignedBlocksWindow(f.ctx)
|
||||
assert.NilError(t, err)
|
||||
f.ctx = f.ctx.WithBlockHeight(signedBlocksWindow + 1).WithHeaderInfo(coreheader.Info{Height: signedBlocksWindow + 1})
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: signedBlocksWindow + 1})
|
||||
assert.NilError(t, f.slashingKeeper.AddrPubkeyRelation.Set(f.ctx, pks[0].Address(), pks[0]))
|
||||
|
||||
consaddr, err := f.stakingKeeper.ConsensusAddressCodec().BytesToString(valpubkey.Address())
|
||||
assert.NilError(t, err)
|
||||
|
||||
info := slashingtypes.NewValidatorSigningInfo(consaddr, f.ctx.BlockHeight(), time.Unix(0, 0), false, int64(0))
|
||||
info := slashingtypes.NewValidatorSigningInfo(consaddr, integration.HeaderInfoFromContext(f.ctx).Height, time.Unix(0, 0), false, int64(0))
|
||||
assert.NilError(t, f.slashingKeeper.ValidatorSigningInfo.Set(f.ctx, sdk.ConsAddress(valpubkey.Address()), info))
|
||||
assert.Equal(t, signedBlocksWindow+1, info.StartHeight)
|
||||
|
||||
@ -300,9 +163,6 @@ func TestHandleNewValidator(t *testing.T) {
|
||||
_, err = f.stakingKeeper.EndBlocker(f.ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
bondDenom, err := f.stakingKeeper.BondDenom(f.ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.DeepEqual(
|
||||
t, f.bankKeeper.GetAllBalances(f.ctx, sdk.AccAddress(addr)),
|
||||
sdk.NewCoins(sdk.NewCoin(bondDenom, testutil.InitTokens.Sub(amt))),
|
||||
@ -314,7 +174,7 @@ func TestHandleNewValidator(t *testing.T) {
|
||||
|
||||
// Now a validator, for two blocks
|
||||
assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, valpubkey.Address(), 100, comet.BlockIDFlagCommit))
|
||||
f.ctx = f.ctx.WithBlockHeight(signedBlocksWindow + 2).WithHeaderInfo(coreheader.Info{Height: signedBlocksWindow + 2})
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: signedBlocksWindow + 2})
|
||||
assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, valpubkey.Address(), 100, comet.BlockIDFlagAbsent))
|
||||
|
||||
info, found := f.slashingKeeper.ValidatorSigningInfo.Get(f.ctx, sdk.ConsAddress(valpubkey.Address()))
|
||||
@ -326,8 +186,7 @@ func TestHandleNewValidator(t *testing.T) {
|
||||
// validator should be bonded still, should not have been jailed or slashed
|
||||
validator, _ := f.stakingKeeper.GetValidatorByConsAddr(f.ctx, sdk.GetConsAddress(valpubkey))
|
||||
assert.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||
bondPool := f.stakingKeeper.GetBondedPool(f.ctx)
|
||||
expTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 100)
|
||||
expTokens := f.stakingKeeper.TokensFromConsensusPower(f.ctx, 100).Add(initialBondPoolBal)
|
||||
assert.Assert(t, expTokens.Equal(f.bankKeeper.GetBalance(f.ctx, bondPool.GetAddress(), bondDenom).Amount))
|
||||
}
|
||||
|
||||
@ -348,7 +207,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
||||
consaddr, err := f.stakingKeeper.ConsensusAddressCodec().BytesToString(val.Address())
|
||||
assert.NilError(t, err)
|
||||
|
||||
info := slashingtypes.NewValidatorSigningInfo(consaddr, f.ctx.HeaderInfo().Height, time.Unix(0, 0), false, int64(0))
|
||||
info := slashingtypes.NewValidatorSigningInfo(consaddr, integration.HeaderInfoFromContext(f.ctx).Height, time.Unix(0, 0), false, int64(0))
|
||||
assert.NilError(t, f.slashingKeeper.ValidatorSigningInfo.Set(f.ctx, sdk.ConsAddress(val.Address()), info))
|
||||
|
||||
acc := f.accountKeeper.NewAccountWithAddress(f.ctx, sdk.AccAddress(addr))
|
||||
@ -365,7 +224,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
||||
// 1000 first blocks OK
|
||||
height := int64(0)
|
||||
for ; height < signedBlocksWindow; height++ {
|
||||
f.ctx = f.ctx.WithHeaderInfo(coreheader.Info{Height: height})
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height})
|
||||
err = f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagCommit)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
@ -375,7 +234,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
||||
|
||||
// 501 blocks missed
|
||||
for ; height < signedBlocksWindow+(signedBlocksWindow-minSignedPerWindow)+1; height++ {
|
||||
f.ctx = f.ctx.WithHeaderInfo(coreheader.Info{Height: height})
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height})
|
||||
err = f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagAbsent)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
@ -393,7 +252,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
||||
assert.DeepEqual(t, resultingTokens, validator.GetTokens())
|
||||
|
||||
// another block missed
|
||||
f.ctx = f.ctx.WithHeaderInfo(coreheader.Info{Height: height})
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height})
|
||||
assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagAbsent))
|
||||
|
||||
// validator should not have been slashed twice
|
||||
@ -432,19 +291,20 @@ func TestValidatorDippingInAndOut(t *testing.T) {
|
||||
consaddrStr, err := f.stakingKeeper.ConsensusAddressCodec().BytesToString(addr)
|
||||
assert.NilError(t, err)
|
||||
|
||||
info := slashingtypes.NewValidatorSigningInfo(consaddrStr, f.ctx.BlockHeight(), time.Unix(0, 0), false, int64(0))
|
||||
info := slashingtypes.NewValidatorSigningInfo(consaddrStr, integration.HeaderInfoFromContext(f.ctx).Height, time.Unix(0, 0), false, int64(0))
|
||||
assert.NilError(t, f.slashingKeeper.ValidatorSigningInfo.Set(f.ctx, consAddr, info))
|
||||
|
||||
tstaking.CreateValidatorWithValPower(valAddr, val, power, true)
|
||||
validatorUpdates, err := f.stakingKeeper.EndBlocker(f.ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(validatorUpdates))
|
||||
// validator updates length should be equal to 2 as we already have one default validator
|
||||
assert.Equal(t, 2, len(validatorUpdates))
|
||||
tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false)
|
||||
|
||||
// 100 first blocks OK
|
||||
height := int64(0)
|
||||
for ; height < int64(100); height++ {
|
||||
f.ctx = f.ctx.WithBlockHeight(height).WithHeaderInfo(coreheader.Info{Height: height})
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height})
|
||||
assert.NilError(t, f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), power, comet.BlockIDFlagCommit))
|
||||
}
|
||||
|
||||
@ -458,8 +318,10 @@ func TestValidatorDippingInAndOut(t *testing.T) {
|
||||
|
||||
// 600 more blocks happened
|
||||
height += 600
|
||||
f.ctx = f.ctx.WithBlockHeight(height).WithHeaderInfo(coreheader.Info{Height: height})
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height})
|
||||
|
||||
// store this height as we don't have block height value in context
|
||||
startHeight := height
|
||||
// validator added back in
|
||||
accAddr, err := f.accountKeeper.AddressCodec().BytesToString(sdk.AccAddress(pks[2].Address()))
|
||||
assert.NilError(t, err)
|
||||
@ -488,7 +350,7 @@ func TestValidatorDippingInAndOut(t *testing.T) {
|
||||
// misses 500 blocks + within the signing windows i.e. 700-1700
|
||||
// validators misses all 1000 blocks of a SignedBlockWindows
|
||||
for ; height < latest+1; height++ {
|
||||
err = f.slashingKeeper.HandleValidatorSignature(f.ctx.WithHeaderInfo(coreheader.Info{Height: height}), val.Address(), newPower, comet.BlockIDFlagAbsent)
|
||||
err = f.slashingKeeper.HandleValidatorSignature(integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height}), val.Address(), newPower, comet.BlockIDFlagAbsent)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
@ -497,7 +359,7 @@ func TestValidatorDippingInAndOut(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, true)
|
||||
|
||||
info = slashingtypes.NewValidatorSigningInfo(consaddrStr, f.ctx.BlockHeight(), time.Unix(0, 0), false, int64(0))
|
||||
info = slashingtypes.NewValidatorSigningInfo(consaddrStr, startHeight, time.Unix(0, 0), false, int64(0))
|
||||
err = f.slashingKeeper.ValidatorSigningInfo.Set(f.ctx, consAddr, info)
|
||||
assert.NilError(t, err)
|
||||
|
||||
@ -510,9 +372,9 @@ func TestValidatorDippingInAndOut(t *testing.T) {
|
||||
|
||||
// some blocks pass
|
||||
height = int64(5000)
|
||||
f.ctx = f.ctx.WithBlockHeight(height).WithHeaderInfo(coreheader.Info{Height: height})
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height})
|
||||
|
||||
info = slashingtypes.NewValidatorSigningInfo(consaddrStr, f.ctx.BlockHeight(), time.Unix(0, 0), false, int64(0))
|
||||
info = slashingtypes.NewValidatorSigningInfo(consaddrStr, integration.HeaderInfoFromContext(f.ctx).Height, time.Unix(0, 0), false, int64(0))
|
||||
err = f.slashingKeeper.ValidatorSigningInfo.Set(f.ctx, consAddr, info)
|
||||
assert.NilError(t, err)
|
||||
|
||||
@ -538,7 +400,7 @@ func TestValidatorDippingInAndOut(t *testing.T) {
|
||||
// validator misses 501 blocks after SignedBlockWindow period (1000 blocks)
|
||||
latest = signedBlocksWindow + height
|
||||
for ; height < latest+minSignedPerWindow; height++ {
|
||||
f.ctx = f.ctx.WithBlockHeight(height).WithHeaderInfo(coreheader.Info{Height: height})
|
||||
f.ctx = integration.SetHeaderInfo(f.ctx, coreheader.Info{Height: height})
|
||||
err = f.slashingKeeper.HandleValidatorSignature(f.ctx, val.Address(), newPower, comet.BlockIDFlagAbsent)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package keeper_test
|
||||
package slashing
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -8,50 +8,24 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/math"
|
||||
bankkeeper "cosmossdk.io/x/bank/keeper"
|
||||
banktestutil "cosmossdk.io/x/bank/testutil"
|
||||
distributionkeeper "cosmossdk.io/x/distribution/keeper"
|
||||
slashingkeeper "cosmossdk.io/x/slashing/keeper"
|
||||
stakingkeeper "cosmossdk.io/x/staking/keeper"
|
||||
stakingtypes "cosmossdk.io/x/staking/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/tests/integration/slashing"
|
||||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
"github.com/cosmos/cosmos-sdk/tests/integration/v2"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
)
|
||||
|
||||
func TestSlashRedelegation(t *testing.T) {
|
||||
// setting up
|
||||
var (
|
||||
authKeeper authkeeper.AccountKeeper
|
||||
stakingKeeper *stakingkeeper.Keeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
slashKeeper slashingkeeper.Keeper
|
||||
distrKeeper distributionkeeper.Keeper
|
||||
)
|
||||
f := initFixture(t)
|
||||
ctx := f.ctx
|
||||
|
||||
app, err := simtestutil.Setup(
|
||||
depinject.Configs(
|
||||
depinject.Supply(log.NewNopLogger()),
|
||||
slashing.AppConfig,
|
||||
),
|
||||
&stakingKeeper,
|
||||
&bankKeeper,
|
||||
&slashKeeper,
|
||||
&distrKeeper,
|
||||
&authKeeper,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// get sdk context, staking msg server and bond denom
|
||||
ctx := app.BaseApp.NewContext(false)
|
||||
stakingMsgServer := stakingkeeper.NewMsgServerImpl(stakingKeeper)
|
||||
bondDenom, err := stakingKeeper.BondDenom(ctx)
|
||||
stakingMsgServer := stakingkeeper.NewMsgServerImpl(f.stakingKeeper)
|
||||
bondDenom, err := f.stakingKeeper.BondDenom(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// evilVal will be slashed, goodVal won't be slashed
|
||||
@ -65,12 +39,12 @@ func TestSlashRedelegation(t *testing.T) {
|
||||
testAcc2 := sdk.AccAddress([]byte("addr2_______________"))
|
||||
|
||||
// fund acc 1 and acc 2
|
||||
testCoin := sdk.NewCoin(bondDenom, stakingKeeper.TokensFromConsensusPower(ctx, 10))
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, testAcc1, testCoin)
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, testAcc2, testCoin)
|
||||
testCoin := sdk.NewCoin(bondDenom, f.stakingKeeper.TokensFromConsensusPower(ctx, 10))
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, testAcc1, testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, testAcc2, testCoin)
|
||||
|
||||
balance1Before := bankKeeper.GetBalance(ctx, testAcc1, bondDenom)
|
||||
balance2Before := bankKeeper.GetBalance(ctx, testAcc2, bondDenom)
|
||||
balance1Before := f.bankKeeper.GetBalance(ctx, testAcc1, bondDenom)
|
||||
balance2Before := f.bankKeeper.GetBalance(ctx, testAcc2, bondDenom)
|
||||
|
||||
// assert acc 1 and acc 2 balance
|
||||
require.Equal(t, balance1Before.Amount.String(), testCoin.Amount.String())
|
||||
@ -78,7 +52,7 @@ func TestSlashRedelegation(t *testing.T) {
|
||||
|
||||
// creating evil val
|
||||
evilValAddr := sdk.ValAddress(evilValPubKey.Address())
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(evilValAddr), testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(evilValAddr), testCoin)
|
||||
createValMsg1, _ := stakingtypes.NewMsgCreateValidator(
|
||||
evilValAddr.String(), evilValPubKey, testCoin, stakingtypes.Description{Details: "test"}, stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)), math.OneInt())
|
||||
_, err = stakingMsgServer.CreateValidator(ctx, createValMsg1)
|
||||
@ -86,16 +60,17 @@ func TestSlashRedelegation(t *testing.T) {
|
||||
|
||||
// creating good val
|
||||
goodValAddr := sdk.ValAddress(goodValPubKey.Address())
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(goodValAddr), testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(goodValAddr), testCoin)
|
||||
createValMsg2, _ := stakingtypes.NewMsgCreateValidator(
|
||||
goodValAddr.String(), goodValPubKey, testCoin, stakingtypes.Description{Details: "test"}, stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)), math.OneInt())
|
||||
_, err = stakingMsgServer.CreateValidator(ctx, createValMsg2)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx = ctx.WithBlockHeight(1).WithHeaderInfo(header.Info{Height: 1})
|
||||
ctx = integration.SetHeaderInfo(ctx, header.Info{Height: 1})
|
||||
// next block, commit height 1, move to height 2
|
||||
// acc 1 and acc 2 delegate to evil val
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state := f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Acc 2 delegate
|
||||
@ -111,13 +86,14 @@ func TestSlashRedelegation(t *testing.T) {
|
||||
// next block, commit height 2, move to height 3
|
||||
// with the new delegations, evil val increases in voting power and commit byzantine behavior at height 3 consensus
|
||||
// at the same time, acc 1 and acc 2 withdraw delegation from evil val
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
evilVal, err := stakingKeeper.GetValidator(ctx, evilValAddr)
|
||||
evilVal, err := f.stakingKeeper.GetValidator(ctx, evilValAddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
evilPower := stakingKeeper.TokensToConsensusPower(ctx, evilVal.Tokens)
|
||||
evilPower := f.stakingKeeper.TokensToConsensusPower(ctx, evilVal.Tokens)
|
||||
|
||||
// Acc 1 redelegate from evil val to good val
|
||||
redelMsg := stakingtypes.NewMsgBeginRedelegate(testAcc1.String(), evilValAddr.String(), goodValAddr.String(), testCoin)
|
||||
@ -135,81 +111,60 @@ func TestSlashRedelegation(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// next block, commit height 3, move to height 4
|
||||
// Slash evil val for byzantine behavior at height 3 consensus,
|
||||
// Slash evil val for byzantine behavior at height 2 consensus,
|
||||
// at which acc 1 and acc 2 still contributed to evil val voting power
|
||||
// even tho they undelegate at block 3, the valset update is applied after committed block 3 when height 3 consensus already passes
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
// slash evil val with slash factor = 0.9, leaving only 10% of stake after slashing
|
||||
evilVal, _ = stakingKeeper.GetValidator(ctx, evilValAddr)
|
||||
evilVal, _ = f.stakingKeeper.GetValidator(ctx, evilValAddr)
|
||||
evilValConsAddr, err := evilVal.GetConsAddr()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = slashKeeper.Slash(ctx, evilValConsAddr, math.LegacyMustNewDecFromStr("0.9"), evilPower, 3)
|
||||
err = f.slashingKeeper.Slash(ctx, evilValConsAddr, math.LegacyMustNewDecFromStr("0.9"), evilPower, 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// assert invariant to make sure we conduct slashing correctly
|
||||
_, stop := stakingkeeper.AllInvariants(stakingKeeper)(ctx)
|
||||
require.False(t, stop)
|
||||
|
||||
_, stop = bankkeeper.AllInvariants(bankKeeper)(ctx)
|
||||
require.False(t, stop)
|
||||
|
||||
_, stop = distributionkeeper.AllInvariants(distrKeeper)(ctx)
|
||||
require.False(t, stop)
|
||||
|
||||
// one eternity later
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1000000000000000000))
|
||||
require.NoError(t, err)
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
ctxHeader := integration.HeaderInfoFromContext(ctx)
|
||||
ctxHeader.Time = ctxHeader.Time.Add(time.Duration(1000000000000000000))
|
||||
ctx = integration.SetHeaderInfo(ctx, ctxHeader)
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
// confirm that account 1 and account 2 has been slashed, and the slash amount is correct
|
||||
balance1AfterSlashing := bankKeeper.GetBalance(ctx, testAcc1, bondDenom)
|
||||
balance2AfterSlashing := bankKeeper.GetBalance(ctx, testAcc2, bondDenom)
|
||||
balance1AfterSlashing := f.bankKeeper.GetBalance(ctx, testAcc1, bondDenom)
|
||||
balance2AfterSlashing := f.bankKeeper.GetBalance(ctx, testAcc2, bondDenom)
|
||||
|
||||
require.Equal(t, balance1AfterSlashing.Amount.Mul(math.NewIntFromUint64(10)).String(), balance1Before.Amount.String())
|
||||
require.Equal(t, balance2AfterSlashing.Amount.Mul(math.NewIntFromUint64(10)).String(), balance2Before.Amount.String())
|
||||
}
|
||||
|
||||
func fundAccount(t *testing.T, ctx context.Context, bankKeeper bankkeeper.Keeper, authKeeper authkeeper.AccountKeeper, addr sdk.AccAddress, amount ...sdk.Coin) {
|
||||
func fundAccount(t *testing.T, ctx context.Context, bankKeeper bankkeeper.Keeper, accountKeeper authkeeper.AccountKeeper, addr sdk.AccAddress, amount ...sdk.Coin) {
|
||||
t.Helper()
|
||||
|
||||
if authKeeper.GetAccount(ctx, addr) == nil {
|
||||
addrAcc := authKeeper.NewAccountWithAddress(ctx, addr)
|
||||
authKeeper.SetAccount(ctx, addrAcc)
|
||||
if accountKeeper.GetAccount(ctx, addr) == nil {
|
||||
addrAcc := accountKeeper.NewAccountWithAddress(ctx, addr)
|
||||
accountKeeper.SetAccount(ctx, addrAcc)
|
||||
}
|
||||
|
||||
require.NoError(t, banktestutil.FundAccount(ctx, bankKeeper, addr, amount))
|
||||
}
|
||||
|
||||
func TestOverSlashing(t *testing.T) {
|
||||
f := initFixture(t)
|
||||
ctx := f.ctx
|
||||
|
||||
// slash penalty percentage
|
||||
slashFraction := "0.45"
|
||||
|
||||
// percentage of (undelegation/(undelegation + redelegation))
|
||||
undelegationPercentageStr := "0.30"
|
||||
|
||||
// setting up
|
||||
var (
|
||||
stakingKeeper *stakingkeeper.Keeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
slashKeeper slashingkeeper.Keeper
|
||||
distrKeeper distributionkeeper.Keeper
|
||||
authKeeper authkeeper.AccountKeeper
|
||||
)
|
||||
|
||||
app, err := simtestutil.Setup(depinject.Configs(
|
||||
depinject.Supply(log.NewNopLogger()),
|
||||
slashing.AppConfig,
|
||||
), &stakingKeeper, &bankKeeper, &slashKeeper, &distrKeeper, &authKeeper)
|
||||
require.NoError(t, err)
|
||||
|
||||
// get sdk context, staking msg server and bond denom
|
||||
ctx := app.BaseApp.NewContext(false)
|
||||
stakingMsgServer := stakingkeeper.NewMsgServerImpl(stakingKeeper)
|
||||
bondDenom, err := stakingKeeper.BondDenom(ctx)
|
||||
stakingMsgServer := stakingkeeper.NewMsgServerImpl(f.stakingKeeper)
|
||||
bondDenom, err := f.stakingKeeper.BondDenom(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// evilVal will be slashed, goodVal won't be slashed
|
||||
@ -231,13 +186,13 @@ func TestOverSlashing(t *testing.T) {
|
||||
|
||||
// fund all accounts
|
||||
testCoin := sdk.NewCoin(bondDenom, math.NewInt(1_000_000))
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, testAcc1, testCoin)
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, testAcc2, testCoin)
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, testAcc3, testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, testAcc1, testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, testAcc2, testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, testAcc3, testCoin)
|
||||
|
||||
balance1Before := bankKeeper.GetBalance(ctx, testAcc1, bondDenom)
|
||||
balance2Before := bankKeeper.GetBalance(ctx, testAcc2, bondDenom)
|
||||
balance3Before := bankKeeper.GetBalance(ctx, testAcc3, bondDenom)
|
||||
balance1Before := f.bankKeeper.GetBalance(ctx, testAcc1, bondDenom)
|
||||
balance2Before := f.bankKeeper.GetBalance(ctx, testAcc2, bondDenom)
|
||||
balance3Before := f.bankKeeper.GetBalance(ctx, testAcc3, bondDenom)
|
||||
|
||||
// assert acc 1, 2 and 3 balance
|
||||
require.Equal(t, testCoin.Amount.String(), balance1Before.Amount.String())
|
||||
@ -246,7 +201,7 @@ func TestOverSlashing(t *testing.T) {
|
||||
|
||||
// create evil val
|
||||
evilValAddr := sdk.ValAddress(evilValPubKey.Address())
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(evilValAddr), testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(evilValAddr), testCoin)
|
||||
createValMsg1, _ := stakingtypes.NewMsgCreateValidator(
|
||||
evilValAddr.String(), evilValPubKey, testCoin, stakingtypes.Description{Details: "test"}, stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)), math.OneInt())
|
||||
_, err = stakingMsgServer.CreateValidator(ctx, createValMsg1)
|
||||
@ -254,15 +209,16 @@ func TestOverSlashing(t *testing.T) {
|
||||
|
||||
// create good val 1
|
||||
goodValAddr := sdk.ValAddress(goodValPubKey.Address())
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(goodValAddr), testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(goodValAddr), testCoin)
|
||||
createValMsg2, _ := stakingtypes.NewMsgCreateValidator(
|
||||
goodValAddr.String(), goodValPubKey, testCoin, stakingtypes.Description{Details: "test"}, stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)), math.OneInt())
|
||||
_, err = stakingMsgServer.CreateValidator(ctx, createValMsg2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// next block
|
||||
ctx = ctx.WithBlockHeight(app.LastBlockHeight() + 1).WithHeaderInfo(header.Info{Height: app.LastBlockHeight() + 1})
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
ctx = integration.SetHeaderInfo(ctx, header.Info{Height: int64(f.app.LastBlockHeight()) + 1})
|
||||
_, state := f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
// delegate all accs to evil val
|
||||
@ -279,21 +235,23 @@ func TestOverSlashing(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// next block
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
// evilValAddr done something bad
|
||||
misbehaveHeight := ctx.BlockHeader().Height
|
||||
evilVal, err := stakingKeeper.GetValidator(ctx, evilValAddr)
|
||||
misbehaveHeight := integration.HeaderInfoFromContext(ctx).Height
|
||||
evilVal, err := f.stakingKeeper.GetValidator(ctx, evilValAddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
evilValConsAddr, err := evilVal.GetConsAddr()
|
||||
require.NoError(t, err)
|
||||
|
||||
evilPower := stakingKeeper.TokensToConsensusPower(ctx, evilVal.Tokens)
|
||||
evilPower := f.stakingKeeper.TokensToConsensusPower(ctx, evilVal.Tokens)
|
||||
|
||||
// next block
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
// acc 1: redelegate to goodval1 and undelegate FULL amount
|
||||
@ -319,7 +277,8 @@ func TestOverSlashing(t *testing.T) {
|
||||
amountToUndelegate := undelegationAmountDec.TruncateInt()
|
||||
|
||||
// next block
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
portionofTestCoins := sdk.NewCoin(bondDenom, amountToUndelegate)
|
||||
@ -328,38 +287,35 @@ func TestOverSlashing(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// next block
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
// slash the evil val
|
||||
err = slashKeeper.Slash(ctx, evilValConsAddr, math.LegacyMustNewDecFromStr(slashFraction), evilPower, misbehaveHeight)
|
||||
err = f.slashingKeeper.Slash(ctx, evilValConsAddr, math.LegacyMustNewDecFromStr(slashFraction), evilPower, misbehaveHeight)
|
||||
require.NoError(t, err)
|
||||
|
||||
// assert invariants
|
||||
_, stop := stakingkeeper.AllInvariants(stakingKeeper)(ctx)
|
||||
require.False(t, stop)
|
||||
_, stop = bankkeeper.AllInvariants(bankKeeper)(ctx)
|
||||
require.False(t, stop)
|
||||
_, stop = distributionkeeper.AllInvariants(distrKeeper)(ctx)
|
||||
require.False(t, stop)
|
||||
|
||||
// fastforward 2 blocks to complete redelegations and unbondings
|
||||
for i := 0; i < 2; i++ {
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1000000000000000000))
|
||||
ctxHeader := integration.HeaderInfoFromContext(ctx)
|
||||
ctxHeader.Time = ctxHeader.Time.Add(time.Duration(1000000000000000000))
|
||||
ctx = integration.SetHeaderInfo(ctx, ctxHeader)
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// we check all accounts should be slashed with the equal amount, and they should end up with same balance including staked amount
|
||||
stakedAcc1, err := stakingKeeper.GetDelegatorBonded(ctx, testAcc1)
|
||||
stakedAcc1, err := f.stakingKeeper.GetDelegatorBonded(ctx, testAcc1)
|
||||
require.NoError(t, err)
|
||||
stakedAcc2, err := stakingKeeper.GetDelegatorBonded(ctx, testAcc2)
|
||||
stakedAcc2, err := f.stakingKeeper.GetDelegatorBonded(ctx, testAcc2)
|
||||
require.NoError(t, err)
|
||||
stakedAcc3, err := stakingKeeper.GetDelegatorBonded(ctx, testAcc3)
|
||||
stakedAcc3, err := f.stakingKeeper.GetDelegatorBonded(ctx, testAcc3)
|
||||
require.NoError(t, err)
|
||||
|
||||
balance1AfterSlashing := bankKeeper.GetBalance(ctx, testAcc1, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc1))
|
||||
balance2AfterSlashing := bankKeeper.GetBalance(ctx, testAcc2, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc2))
|
||||
balance3AfterSlashing := bankKeeper.GetBalance(ctx, testAcc3, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc3))
|
||||
balance1AfterSlashing := f.bankKeeper.GetBalance(ctx, testAcc1, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc1))
|
||||
balance2AfterSlashing := f.bankKeeper.GetBalance(ctx, testAcc2, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc2))
|
||||
balance3AfterSlashing := f.bankKeeper.GetBalance(ctx, testAcc3, bondDenom).Add(sdk.NewCoin(bondDenom, stakedAcc3))
|
||||
|
||||
require.Equal(t, "550000stake", balance1AfterSlashing.String())
|
||||
require.Equal(t, "550000stake", balance2AfterSlashing.String())
|
||||
@ -367,32 +323,11 @@ func TestOverSlashing(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) {
|
||||
// setting up
|
||||
var (
|
||||
authKeeper authkeeper.AccountKeeper
|
||||
stakingKeeper *stakingkeeper.Keeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
slashKeeper slashingkeeper.Keeper
|
||||
distrKeeper distributionkeeper.Keeper
|
||||
)
|
||||
f := initFixture(t)
|
||||
ctx := f.ctx
|
||||
|
||||
app, err := simtestutil.Setup(
|
||||
depinject.Configs(
|
||||
depinject.Supply(log.NewNopLogger()),
|
||||
slashing.AppConfig,
|
||||
),
|
||||
&stakingKeeper,
|
||||
&bankKeeper,
|
||||
&slashKeeper,
|
||||
&distrKeeper,
|
||||
&authKeeper,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// get sdk context, staking msg server and bond denom
|
||||
ctx := app.BaseApp.NewContext(false).WithBlockHeight(1).WithHeaderInfo(header.Info{Height: 1})
|
||||
stakingMsgServer := stakingkeeper.NewMsgServerImpl(stakingKeeper)
|
||||
bondDenom, err := stakingKeeper.BondDenom(ctx)
|
||||
stakingMsgServer := stakingkeeper.NewMsgServerImpl(f.stakingKeeper)
|
||||
bondDenom, err := f.stakingKeeper.BondDenom(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// create validators DST and SRC
|
||||
@ -402,9 +337,9 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) {
|
||||
dstAddr := sdk.ValAddress(dstPubKey.Address())
|
||||
srcAddr := sdk.ValAddress(srcPubKey.Address())
|
||||
|
||||
testCoin := sdk.NewCoin(bondDenom, stakingKeeper.TokensFromConsensusPower(ctx, 1000))
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(dstAddr), testCoin)
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, sdk.AccAddress(srcAddr), testCoin)
|
||||
testCoin := sdk.NewCoin(bondDenom, f.stakingKeeper.TokensFromConsensusPower(ctx, 1000))
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(dstAddr), testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, sdk.AccAddress(srcAddr), testCoin)
|
||||
|
||||
createValMsgDST, _ := stakingtypes.NewMsgCreateValidator(
|
||||
dstAddr.String(), dstPubKey, testCoin, stakingtypes.Description{Details: "Validator DST"}, stakingtypes.NewCommissionRates(math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDec(0)), math.OneInt())
|
||||
@ -418,10 +353,10 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) {
|
||||
|
||||
// create a user accounts and delegate to SRC and DST
|
||||
userAcc := sdk.AccAddress([]byte("user1_______________"))
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, userAcc, testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, userAcc, testCoin)
|
||||
|
||||
userAcc2 := sdk.AccAddress([]byte("user2_______________"))
|
||||
fundAccount(t, ctx, bankKeeper, authKeeper, userAcc2, testCoin)
|
||||
fundAccount(t, ctx, f.bankKeeper, f.accountKeeper, userAcc2, testCoin)
|
||||
|
||||
delMsg := stakingtypes.NewMsgDelegate(userAcc.String(), srcAddr.String(), testCoin)
|
||||
_, err = stakingMsgServer.Delegate(ctx, delMsg)
|
||||
@ -431,18 +366,20 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) {
|
||||
_, err = stakingMsgServer.Delegate(ctx, delMsg)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state := f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
// commit an infraction with DST and store the power at this height
|
||||
dstVal, err := stakingKeeper.GetValidator(ctx, dstAddr)
|
||||
dstVal, err := f.stakingKeeper.GetValidator(ctx, dstAddr)
|
||||
require.NoError(t, err)
|
||||
dstPower := stakingKeeper.TokensToConsensusPower(ctx, dstVal.Tokens)
|
||||
dstPower := f.stakingKeeper.TokensToConsensusPower(ctx, dstVal.Tokens)
|
||||
dstConsAddr, err := dstVal.GetConsAddr()
|
||||
require.NoError(t, err)
|
||||
dstInfractionHeight := ctx.BlockHeight()
|
||||
dstInfractionHeight := f.app.LastBlockHeight() + 1
|
||||
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
// undelegate all the user tokens from DST
|
||||
@ -451,14 +388,15 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// commit an infraction with SRC and store the power at this height
|
||||
srcVal, err := stakingKeeper.GetValidator(ctx, srcAddr)
|
||||
srcVal, err := f.stakingKeeper.GetValidator(ctx, srcAddr)
|
||||
require.NoError(t, err)
|
||||
srcPower := stakingKeeper.TokensToConsensusPower(ctx, srcVal.Tokens)
|
||||
srcPower := f.stakingKeeper.TokensToConsensusPower(ctx, srcVal.Tokens)
|
||||
srcConsAddr, err := srcVal.GetConsAddr()
|
||||
require.NoError(t, err)
|
||||
srcInfractionHeight := ctx.BlockHeight()
|
||||
srcInfractionHeight := f.app.LastBlockHeight() + 1
|
||||
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
// redelegate all the user tokens from SRC to DST
|
||||
@ -471,7 +409,8 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) {
|
||||
_, err = stakingMsgServer.Undelegate(ctx, undelMsg)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx, err = simtestutil.NextBlock(app, ctx, time.Duration(1))
|
||||
_, state = f.app.Deliver(t, ctx, nil)
|
||||
_, err = f.app.Commit(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
undelMsg = stakingtypes.NewMsgUndelegate(userAcc.String(), dstAddr.String(), testCoin)
|
||||
@ -479,24 +418,14 @@ func TestSlashRedelegation_ValidatorLeftWithNoTokens(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// check that dst now has zero tokens
|
||||
valDst, err := stakingKeeper.GetValidator(ctx, dstAddr)
|
||||
valDst, err := f.stakingKeeper.GetValidator(ctx, dstAddr)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, math.ZeroInt().String(), valDst.Tokens.String())
|
||||
|
||||
// slash the infractions
|
||||
err = slashKeeper.Slash(ctx, dstConsAddr, math.LegacyMustNewDecFromStr("0.8"), dstPower, dstInfractionHeight)
|
||||
err = f.slashingKeeper.Slash(ctx, dstConsAddr, math.LegacyMustNewDecFromStr("0.8"), dstPower, int64(dstInfractionHeight))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = slashKeeper.Slash(ctx, srcConsAddr, math.LegacyMustNewDecFromStr("0.5"), srcPower, srcInfractionHeight)
|
||||
err = f.slashingKeeper.Slash(ctx, srcConsAddr, math.LegacyMustNewDecFromStr("0.5"), srcPower, int64(srcInfractionHeight))
|
||||
require.NoError(t, err)
|
||||
|
||||
// assert invariants to ensure correctness
|
||||
_, stop := stakingkeeper.AllInvariants(stakingKeeper)(ctx)
|
||||
require.False(t, stop)
|
||||
|
||||
_, stop = bankkeeper.AllInvariants(bankKeeper)(ctx)
|
||||
require.False(t, stop)
|
||||
|
||||
_, stop = distributionkeeper.AllInvariants(distrKeeper)(ctx)
|
||||
require.False(t, stop)
|
||||
}
|
||||
175
tests/integration/v2/slashing/slashing_test.go
Normal file
175
tests/integration/v2/slashing/slashing_test.go
Normal file
@ -0,0 +1,175 @@
|
||||
package slashing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/math"
|
||||
_ "cosmossdk.io/x/accounts" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/bank" // import as blank for app wiring
|
||||
bankkeeper "cosmossdk.io/x/bank/keeper"
|
||||
banktestutil "cosmossdk.io/x/bank/testutil"
|
||||
_ "cosmossdk.io/x/consensus" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/distribution" // import as blank for app wiring
|
||||
distrkeeper "cosmossdk.io/x/distribution/keeper"
|
||||
_ "cosmossdk.io/x/mint" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/protocolpool" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/slashing" // import as blank for app wiring
|
||||
slashingkeeper "cosmossdk.io/x/slashing/keeper"
|
||||
"cosmossdk.io/x/slashing/testutil"
|
||||
slashingtypes "cosmossdk.io/x/slashing/types"
|
||||
_ "cosmossdk.io/x/staking" // import as blank for app wiring
|
||||
stakingkeeper "cosmossdk.io/x/staking/keeper"
|
||||
stakingtypes "cosmossdk.io/x/staking/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
codecaddress "github.com/cosmos/cosmos-sdk/codec/address"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/tests/integration/v2"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/configurator"
|
||||
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/auth" // import as blank for app wiring
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import as blank for app wiring
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
_ "github.com/cosmos/cosmos-sdk/x/genutil" // import as blank for app wiring
|
||||
)
|
||||
|
||||
var (
|
||||
priv1 = secp256k1.GenPrivKey()
|
||||
addr1 = sdk.AccAddress(priv1.PubKey().Address())
|
||||
valaddrCodec = codecaddress.NewBech32Codec("cosmosvaloper")
|
||||
|
||||
valKey = ed25519.GenPrivKey()
|
||||
valAddr = sdk.AccAddress(valKey.PubKey().Address())
|
||||
)
|
||||
|
||||
type fixture struct {
|
||||
app *integration.App
|
||||
|
||||
ctx context.Context
|
||||
|
||||
accountKeeper authkeeper.AccountKeeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
slashingKeeper slashingkeeper.Keeper
|
||||
stakingKeeper *stakingkeeper.Keeper
|
||||
distrKeeper distrkeeper.Keeper
|
||||
|
||||
slashingMsgServer slashingtypes.MsgServer
|
||||
txConfig client.TxConfig
|
||||
|
||||
valAddrs []sdk.ValAddress
|
||||
}
|
||||
|
||||
func initFixture(t *testing.T) *fixture {
|
||||
t.Helper()
|
||||
|
||||
res := fixture{}
|
||||
|
||||
moduleConfigs := []configurator.ModuleOption{
|
||||
configurator.AccountsModule(),
|
||||
configurator.AuthModule(),
|
||||
configurator.BankModule(),
|
||||
configurator.StakingModule(),
|
||||
configurator.SlashingModule(),
|
||||
configurator.TxModule(),
|
||||
configurator.ValidateModule(),
|
||||
configurator.ConsensusModule(),
|
||||
configurator.GenutilModule(),
|
||||
configurator.MintModule(),
|
||||
configurator.DistributionModule(),
|
||||
configurator.ProtocolPoolModule(),
|
||||
}
|
||||
|
||||
acc := &authtypes.BaseAccount{
|
||||
Address: addr1.String(),
|
||||
}
|
||||
|
||||
var err error
|
||||
startupCfg := integration.DefaultStartUpConfig(t)
|
||||
startupCfg.GenesisAccounts = []integration.GenesisAccount{{GenesisAccount: acc}}
|
||||
|
||||
startupCfg.BranchService = &integration.BranchService{}
|
||||
startupCfg.HeaderService = &integration.HeaderService{}
|
||||
|
||||
res.app, err = integration.NewApp(
|
||||
depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Supply(log.NewNopLogger())),
|
||||
startupCfg,
|
||||
&res.bankKeeper, &res.accountKeeper, &res.stakingKeeper, &res.slashingKeeper, &res.distrKeeper, &res.txConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
res.ctx = res.app.StateLatestContext(t)
|
||||
|
||||
// set default staking params
|
||||
// TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500
|
||||
err = res.slashingKeeper.Params.Set(res.ctx, testutil.TestParams())
|
||||
assert.NilError(t, err)
|
||||
|
||||
addrDels := simtestutil.AddTestAddrsIncremental(res.bankKeeper, res.stakingKeeper, res.ctx, 6, res.stakingKeeper.TokensFromConsensusPower(res.ctx, 200))
|
||||
valAddrs := simtestutil.ConvertAddrsToValAddrs(addrDels)
|
||||
|
||||
consaddr0, err := res.stakingKeeper.ConsensusAddressCodec().BytesToString(addrDels[0])
|
||||
require.NoError(t, err)
|
||||
consaddr1, err := res.stakingKeeper.ConsensusAddressCodec().BytesToString(addrDels[1])
|
||||
require.NoError(t, err)
|
||||
|
||||
info1 := slashingtypes.NewValidatorSigningInfo(consaddr0, int64(4), time.Unix(2, 0), false, int64(10))
|
||||
info2 := slashingtypes.NewValidatorSigningInfo(consaddr1, int64(5), time.Unix(2, 0), false, int64(10))
|
||||
|
||||
err = res.slashingKeeper.ValidatorSigningInfo.Set(res.ctx, sdk.ConsAddress(addrDels[0]), info1)
|
||||
require.NoError(t, err)
|
||||
err = res.slashingKeeper.ValidatorSigningInfo.Set(res.ctx, sdk.ConsAddress(addrDels[1]), info2)
|
||||
require.NoError(t, err)
|
||||
|
||||
res.valAddrs = valAddrs
|
||||
res.slashingMsgServer = slashingkeeper.NewMsgServerImpl(res.slashingKeeper)
|
||||
|
||||
return &res
|
||||
}
|
||||
|
||||
func TestSlashingMsgs(t *testing.T) {
|
||||
f := initFixture(t)
|
||||
|
||||
genTokens := sdk.TokensFromConsensusPower(42, sdk.DefaultPowerReduction)
|
||||
bondTokens := sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction)
|
||||
genCoin := sdk.NewCoin(sdk.DefaultBondDenom, genTokens)
|
||||
bondCoin := sdk.NewCoin(sdk.DefaultBondDenom, bondTokens)
|
||||
|
||||
require.NoError(t, banktestutil.FundAccount(f.ctx, f.bankKeeper, addr1, sdk.NewCoins(genCoin)))
|
||||
|
||||
description := stakingtypes.NewDescription("foo_moniker", "", "", "", "", &stakingtypes.Metadata{})
|
||||
commission := stakingtypes.NewCommissionRates(math.LegacyZeroDec(), math.LegacyZeroDec(), math.LegacyZeroDec())
|
||||
|
||||
addrStrVal, err := valaddrCodec.BytesToString(addr1)
|
||||
require.NoError(t, err)
|
||||
createValidatorMsg, err := stakingtypes.NewMsgCreateValidator(
|
||||
addrStrVal, valKey.PubKey(), bondCoin, description, commission, math.OneInt(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = f.app.SignCheckDeliver(t, f.ctx, []sdk.Msg{createValidatorMsg}, "", []uint64{0}, []uint64{0}, []cryptotypes.PrivKey{priv1}, "")
|
||||
require.True(t, sdk.Coins{genCoin.Sub(bondCoin)}.Equal(f.bankKeeper.GetAllBalances(f.ctx, addr1)))
|
||||
|
||||
validator, err := f.stakingKeeper.GetValidator(f.ctx, sdk.ValAddress(addr1))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, addrStrVal, validator.OperatorAddress)
|
||||
require.Equal(t, stakingtypes.Bonded, validator.Status)
|
||||
require.True(math.IntEq(t, bondTokens, validator.BondedTokens()))
|
||||
unjailMsg := &slashingtypes.MsgUnjail{ValidatorAddr: addrStrVal}
|
||||
|
||||
_, err = f.slashingKeeper.ValidatorSigningInfo.Get(f.ctx, sdk.ConsAddress(valAddr))
|
||||
require.NoError(t, err)
|
||||
|
||||
// unjail should fail with validator not jailed error
|
||||
_ = f.app.SignCheckDeliver(t, f.ctx, []sdk.Msg{unjailMsg}, "", []uint64{0}, []uint64{1}, []cryptotypes.PrivKey{priv1}, slashingtypes.ErrValidatorNotJailed.Error())
|
||||
}
|
||||
@ -2,6 +2,7 @@ package sims
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"strconv"
|
||||
@ -20,7 +21,7 @@ const mintModuleName = "mint"
|
||||
type GenerateAccountStrategy func(int) []sdk.AccAddress
|
||||
|
||||
// AddTestAddrsFromPubKeys adds the addresses into the SimApp providing only the public keys.
|
||||
func AddTestAddrsFromPubKeys(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx sdk.Context, pubKeys []cryptotypes.PubKey, accAmt math.Int) {
|
||||
func AddTestAddrsFromPubKeys(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx context.Context, pubKeys []cryptotypes.PubKey, accAmt math.Int) {
|
||||
bondDenom, err := stakingKeeper.BondDenom(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -39,11 +40,11 @@ func AddTestAddrs(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx sdk.Co
|
||||
}
|
||||
|
||||
// AddTestAddrsIncremental constructs and returns accNum amount of accounts with an initial balance of accAmt in random order
|
||||
func AddTestAddrsIncremental(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx sdk.Context, accNum int, accAmt math.Int) []sdk.AccAddress {
|
||||
func AddTestAddrsIncremental(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx context.Context, accNum int, accAmt math.Int) []sdk.AccAddress {
|
||||
return addTestAddrs(bankKeeper, stakingKeeper, ctx, accNum, accAmt, CreateIncrementalAccounts)
|
||||
}
|
||||
|
||||
func addTestAddrs(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx sdk.Context, accNum int, accAmt math.Int, strategy GenerateAccountStrategy) []sdk.AccAddress {
|
||||
func addTestAddrs(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx context.Context, accNum int, accAmt math.Int, strategy GenerateAccountStrategy) []sdk.AccAddress {
|
||||
testAddrs := strategy(accNum)
|
||||
bondDenom, err := stakingKeeper.BondDenom(ctx)
|
||||
if err != nil {
|
||||
@ -58,7 +59,7 @@ func addTestAddrs(bankKeeper BankKeeper, stakingKeeper StakingKeeper, ctx sdk.Co
|
||||
return testAddrs
|
||||
}
|
||||
|
||||
func initAccountWithCoins(bankKeeper BankKeeper, ctx sdk.Context, addr sdk.AccAddress, coins sdk.Coins) {
|
||||
func initAccountWithCoins(bankKeeper BankKeeper, ctx context.Context, addr sdk.AccAddress, coins sdk.Coins) {
|
||||
if err := bankKeeper.MintCoins(ctx, mintModuleName, coins); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user