package simulation_test import ( "fmt" "math/rand" "testing" "time" abci "git.cw.tr/mukan-network/mukan-consensus/abci/types" cmttypes "git.cw.tr/mukan-network/mukan-consensus/types" "github.com/cosmos/gogoproto/proto" "github.com/stretchr/testify/suite" "cosmossdk.io/depinject" "cosmossdk.io/log" "cosmossdk.io/math" "git.cw.tr/mukan-network/mukan-sdk/client" "git.cw.tr/mukan-network/mukan-sdk/codec" codectypes "git.cw.tr/mukan-network/mukan-sdk/codec/types" cryptocodec "git.cw.tr/mukan-network/mukan-sdk/crypto/codec" "git.cw.tr/mukan-network/mukan-sdk/runtime" simtestutil "git.cw.tr/mukan-network/mukan-sdk/testutil/sims" sdk "git.cw.tr/mukan-network/mukan-sdk/types" simtypes "git.cw.tr/mukan-network/mukan-sdk/types/simulation" authkeeper "git.cw.tr/mukan-network/mukan-sdk/x/auth/keeper" bankkeeper "git.cw.tr/mukan-network/mukan-sdk/x/bank/keeper" banktestutil "git.cw.tr/mukan-network/mukan-sdk/x/bank/testutil" distributionkeeper "git.cw.tr/mukan-network/mukan-sdk/x/distribution/keeper" distrtypes "git.cw.tr/mukan-network/mukan-sdk/x/distribution/types" mintkeeper "git.cw.tr/mukan-network/mukan-sdk/x/mint/keeper" minttypes "git.cw.tr/mukan-network/mukan-sdk/x/mint/types" slashingkeeper "git.cw.tr/mukan-network/mukan-sdk/x/slashing/keeper" "git.cw.tr/mukan-network/mukan-sdk/x/slashing/simulation" "git.cw.tr/mukan-network/mukan-sdk/x/slashing/testutil" "git.cw.tr/mukan-network/mukan-sdk/x/slashing/types" stakingkeeper "git.cw.tr/mukan-network/mukan-sdk/x/staking/keeper" stakingtypes "git.cw.tr/mukan-network/mukan-sdk/x/staking/types" ) type SimTestSuite struct { suite.Suite ctx sdk.Context r *rand.Rand accounts []simtypes.Account app *runtime.App legacyAmino *codec.LegacyAmino codec codec.Codec interfaceRegistry codectypes.InterfaceRegistry txConfig client.TxConfig accountKeeper authkeeper.AccountKeeper bankKeeper bankkeeper.Keeper stakingKeeper *stakingkeeper.Keeper slashingKeeper slashingkeeper.Keeper distrKeeper distributionkeeper.Keeper mintKeeper mintkeeper.Keeper } func (suite *SimTestSuite) SetupTest() { s := rand.NewSource(1) suite.r = rand.New(s) accounts := simtypes.RandomAccounts(suite.r, 4) // create validator (non random as using a seed) createValidator := func() (*cmttypes.ValidatorSet, error) { account := accounts[0] cmtPk, err := cryptocodec.ToCmtPubKeyInterface(account.PubKey) if err != nil { return nil, fmt.Errorf("failed to create pubkey: %w", err) } validator := cmttypes.NewValidator(cmtPk, 1) return cmttypes.NewValidatorSet([]*cmttypes.Validator{validator}), nil } startupCfg := simtestutil.DefaultStartUpConfig() startupCfg.ValidatorSet = createValidator app, err := simtestutil.SetupWithConfiguration( depinject.Configs( testutil.AppConfig, depinject.Supply(log.NewNopLogger()), ), startupCfg, &suite.legacyAmino, &suite.codec, &suite.interfaceRegistry, &suite.txConfig, &suite.accountKeeper, &suite.bankKeeper, &suite.stakingKeeper, &suite.mintKeeper, &suite.slashingKeeper, &suite.distrKeeper, ) suite.Require().NoError(err) suite.app = app suite.ctx = app.NewContext(false) // remove genesis validator account suite.accounts = accounts[1:] initAmt := suite.stakingKeeper.TokensFromConsensusPower(suite.ctx, 200) initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) // add coins to the accounts for _, account := range suite.accounts { acc := suite.accountKeeper.NewAccountWithAddress(suite.ctx, account.Address) suite.accountKeeper.SetAccount(suite.ctx, acc) suite.Require().NoError(banktestutil.FundAccount(suite.ctx, suite.bankKeeper, account.Address, initCoins)) } suite.Require().NoError(suite.mintKeeper.Params.Set(suite.ctx, minttypes.DefaultParams())) suite.Require().NoError(suite.mintKeeper.Minter.Set(suite.ctx, minttypes.DefaultInitialMinter())) } func TestSimTestSuite(t *testing.T) { suite.Run(t, new(SimTestSuite)) } // TestWeightedOperations tests the weights of the operations. func (suite *SimTestSuite) TestWeightedOperations() { ctx := suite.ctx.WithChainID("test-chain") appParams := make(simtypes.AppParams) expected := []struct { weight int opMsgRoute string opMsgName string }{ {simulation.DefaultWeightMsgUnjail, types.ModuleName, sdk.MsgTypeURL(&types.MsgUnjail{})}, } weightedOps := simulation.WeightedOperations(suite.interfaceRegistry, appParams, suite.codec, suite.txConfig, suite.accountKeeper, suite.bankKeeper, suite.slashingKeeper, suite.stakingKeeper) for i, w := range weightedOps { operationMsg, _, err := w.Op()(suite.r, suite.app.BaseApp, ctx, suite.accounts, ctx.ChainID()) suite.Require().NoError(err) // 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 suite.Require().Equal(expected[i].weight, w.Weight(), "weight should be the same") suite.Require().Equal(expected[i].opMsgRoute, operationMsg.Route, "route should be the same") suite.Require().Equal(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 (suite *SimTestSuite) TestSimulateMsgUnjail() { blockTime := time.Now().UTC() ctx := suite.ctx.WithBlockTime(blockTime) // setup accounts[0] as validator0 validator0, err := getTestingValidator0(ctx, suite.stakingKeeper, suite.accounts) suite.Require().NoError(err) // setup validator0 by consensus address suite.Require().NoError(suite.stakingKeeper.SetValidatorByConsAddr(ctx, validator0)) val0ConsAddress, err := validator0.GetConsAddr() suite.Require().NoError(err) info := types.NewValidatorSigningInfo(val0ConsAddress, int64(4), int64(3), time.Unix(2, 0), false, int64(10)) suite.Require().NoError(suite.slashingKeeper.SetValidatorSigningInfo(ctx, val0ConsAddress, info)) // put validator0 in jail suite.Require().NoError(suite.stakingKeeper.Jail(ctx, val0ConsAddress)) // setup self delegation delTokens := suite.stakingKeeper.TokensFromConsensusPower(ctx, 2) validator0, issuedShares := validator0.AddTokensFromDel(delTokens) val0AccAddress, err := sdk.ValAddressFromBech32(validator0.OperatorAddress) suite.Require().NoError(err) selfDelegation := stakingtypes.NewDelegation(suite.accounts[0].Address.String(), validator0.GetOperator(), issuedShares) suite.Require().NoError(suite.stakingKeeper.SetDelegation(ctx, selfDelegation)) suite.Require().NoError(suite.distrKeeper.SetDelegatorStartingInfo(ctx, val0AccAddress, val0AccAddress.Bytes(), distrtypes.NewDelegatorStartingInfo(2, math.LegacyOneDec(), 200))) // begin a new block _, err = suite.app.FinalizeBlock(&abci.RequestFinalizeBlock{Height: suite.app.LastBlockHeight() + 1, Hash: suite.app.LastCommitID().Hash, Time: blockTime}) suite.Require().NoError(err) // execute operation op := simulation.SimulateMsgUnjail(codec.NewProtoCodec(suite.interfaceRegistry), suite.txConfig, suite.accountKeeper, suite.bankKeeper, suite.slashingKeeper, suite.stakingKeeper) operationMsg, futureOperations, err := op(suite.r, suite.app.BaseApp, ctx, suite.accounts, "") suite.Require().NoError(err) var msg types.MsgUnjail err = proto.Unmarshal(operationMsg.Msg, &msg) suite.Require().NoError(err) suite.Require().True(operationMsg.OK) suite.Require().Equal("cosmosvaloper1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7epjs3u", msg.ValidatorAddr) suite.Require().Len(futureOperations, 0) } func getTestingValidator0(ctx sdk.Context, stakingKeeper *stakingkeeper.Keeper, accounts []simtypes.Account) (stakingtypes.Validator, error) { commission0 := stakingtypes.NewCommission(math.LegacyZeroDec(), math.LegacyOneDec(), math.LegacyOneDec()) return getTestingValidator(ctx, stakingKeeper, accounts, commission0, 0) } func getTestingValidator(ctx sdk.Context, stakingKeeper *stakingkeeper.Keeper, accounts []simtypes.Account, commission stakingtypes.Commission, n int) (stakingtypes.Validator, error) { account := accounts[n] valPubKey := account.ConsKey.PubKey() valAddr := sdk.ValAddress(account.PubKey.Address().Bytes()) validator, err := stakingtypes.NewValidator(valAddr.String(), valPubKey, stakingtypes.Description{}) if err != nil { return stakingtypes.Validator{}, fmt.Errorf("failed to create validator: %w", err) } validator, err = validator.SetInitialCommission(commission) if err != nil { return stakingtypes.Validator{}, fmt.Errorf("failed to set initial commission: %w", err) } validator.DelegatorShares = math.LegacyNewDec(100) validator.Tokens = math.NewInt(1000000) err = stakingKeeper.SetValidator(ctx, validator) if err != nil { return stakingtypes.Validator{}, fmt.Errorf("failed to set validator: %w", err) } return validator, nil }