diff --git a/x/slashing/simulation/operation_test.go b/x/slashing/simulation/operation_test.go new file mode 100644 index 0000000000..0987daadb2 --- /dev/null +++ b/x/slashing/simulation/operation_test.go @@ -0,0 +1,149 @@ +package simulation_test + +import ( + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/cosmos/cosmos-sdk/x/slashing/simulation" + "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// TestWeightedOperations tests the weights of the operations. +func TestWeightedOperations(t *testing.T) { + app, ctx := createTestApp(false) + ctx.WithChainID("test-chain") + + cdc := app.Codec() + appParams := make(simtypes.AppParams) + + s := rand.NewSource(1) + r := rand.New(s) + accs := simtypes.RandomAccounts(r, 3) + + expected := []struct { + weight int + opMsgRoute string + opMsgName string + }{{simappparams.DefaultWeightMsgUnjail, types.ModuleName, types.TypeMsgUnjail}} + + weightesOps := simulation.WeightedOperations(appParams, cdc, app.AccountKeeper, app.BankKeeper, app.SlashingKeeper, app.StakingKeeper) + for i, w := range weightesOps { + operationMsg, _, _ := w.Op()(r, app.BaseApp, ctx, accs, ctx.ChainID()) + // the following checks are very much dependent from the ordering of the output given + // by WeightedOperations. if the ordering in WeightedOperations changes some tests + // will fail + require.Equal(t, expected[i].weight, w.Weight(), "weight should be the same") + require.Equal(t, expected[i].opMsgRoute, operationMsg.Route, "route should be the same") + require.Equal(t, expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same") + } +} + +// TestSimulateMsgUnjail tests the normal scenario of a valid message of type types.MsgUnjail. +// Abonormal scenarios, where the message is created by an errors, are not tested here. +func TestSimulateMsgUnjail(t *testing.T) { + app, ctx := createTestApp(false) + blockTime := time.Now().UTC() + ctx = ctx.WithBlockTime(blockTime) + + // setup 3 accounts + s := rand.NewSource(1) + r := rand.New(s) + accounts := getTestingAccounts(t, r, app, ctx, 3) + + // setup accounts[0] as validator0 + validator0 := getTestingValidator0(t, app, ctx, accounts) + + // setup validator0 by consensus address + app.StakingKeeper.SetValidatorByConsAddr(ctx, validator0) + val0ConsAddress := sdk.ConsAddress(validator0.GetConsPubKey().Address()) + info := types.NewValidatorSigningInfo(val0ConsAddress, int64(4), int64(3), + time.Unix(2, 0), false, int64(10)) + app.SlashingKeeper.SetValidatorSigningInfo(ctx, val0ConsAddress, info) + + // put validator0 in jail + app.StakingKeeper.Jail(ctx, val0ConsAddress) + + // setup self delegation + delTokens := sdk.TokensFromConsensusPower(2) + validator0, issuedShares := validator0.AddTokensFromDel(delTokens) + val0AccAddress := sdk.AccAddress(validator0.OperatorAddress.Bytes()) + selfDelegation := stakingtypes.NewDelegation(val0AccAddress, validator0.OperatorAddress, issuedShares) + app.StakingKeeper.SetDelegation(ctx, selfDelegation) + app.DistrKeeper.SetDelegatorStartingInfo(ctx, validator0.OperatorAddress, val0AccAddress, distrtypes.NewDelegatorStartingInfo(2, sdk.OneDec(), 200)) + + // begin a new block + app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}}) + + // execute operation + op := simulation.SimulateMsgUnjail(app.AccountKeeper, app.BankKeeper, app.SlashingKeeper, app.StakingKeeper) + operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "") + require.NoError(t, err) + + var msg types.MsgUnjail + types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg) + + require.True(t, operationMsg.OK) + require.Equal(t, types.TypeMsgUnjail, msg.Type()) + require.Equal(t, "cosmosvaloper1tnh2q55v8wyygtt9srz5safamzdengsn9dsd7z", msg.GetValidatorAddr().String()) + require.Len(t, futureOperations, 0) +} + +// returns context and an app with updated mint keeper +func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { + app := simapp.Setup(isCheckTx) + + ctx := app.BaseApp.NewContext(isCheckTx, abci.Header{}) + app.MintKeeper.SetParams(ctx, minttypes.DefaultParams()) + app.MintKeeper.SetMinter(ctx, minttypes.DefaultInitialMinter()) + + return app, ctx +} + +func getTestingAccounts(t *testing.T, r *rand.Rand, app *simapp.SimApp, ctx sdk.Context, n int) []simtypes.Account { + accounts := simtypes.RandomAccounts(r, n) + + initAmt := sdk.TokensFromConsensusPower(200) + initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) + + // add coins to the accounts + for _, account := range accounts { + acc := app.AccountKeeper.NewAccountWithAddress(ctx, account.Address) + app.AccountKeeper.SetAccount(ctx, acc) + err := app.BankKeeper.SetBalances(ctx, account.Address, initCoins) + require.NoError(t, err) + } + + return accounts +} + +func getTestingValidator0(t *testing.T, app *simapp.SimApp, ctx sdk.Context, accounts []simtypes.Account) stakingtypes.Validator { + commission0 := stakingtypes.NewCommission(sdk.ZeroDec(), sdk.OneDec(), sdk.OneDec()) + return getTestingValidator(t, app, ctx, accounts, commission0, 0) +} + +func getTestingValidator(t *testing.T, app *simapp.SimApp, ctx sdk.Context, accounts []simtypes.Account, commission stakingtypes.Commission, n int) stakingtypes.Validator { + account := accounts[n] + valPubKey := account.PubKey + valAddr := sdk.ValAddress(account.PubKey.Address().Bytes()) + validator := stakingtypes.NewValidator(valAddr, valPubKey, stakingtypes.Description{}) + validator, err := validator.SetInitialCommission(commission) + require.NoError(t, err) + + validator.DelegatorShares = sdk.NewDec(100) + validator.Tokens = sdk.NewInt(1000000) + + app.StakingKeeper.SetValidator(ctx, validator) + + return validator +}