github.com/cosmos/cosmos-sdk@v0.50.10/x/slashing/simulation/operations.go (about) 1 package simulation 2 3 import ( 4 "errors" 5 "math/rand" 6 7 "github.com/cosmos/cosmos-sdk/baseapp" 8 "github.com/cosmos/cosmos-sdk/client" 9 "github.com/cosmos/cosmos-sdk/codec" 10 codectypes "github.com/cosmos/cosmos-sdk/codec/types" 11 "github.com/cosmos/cosmos-sdk/testutil" 12 simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" 13 sdk "github.com/cosmos/cosmos-sdk/types" 14 simtypes "github.com/cosmos/cosmos-sdk/types/simulation" 15 "github.com/cosmos/cosmos-sdk/x/simulation" 16 "github.com/cosmos/cosmos-sdk/x/slashing/keeper" 17 "github.com/cosmos/cosmos-sdk/x/slashing/types" 18 ) 19 20 // Simulation operation weights constants 21 const ( 22 OpWeightMsgUnjail = "op_weight_msg_unjail" 23 24 DefaultWeightMsgUnjail = 100 25 ) 26 27 // WeightedOperations returns all the operations from the module with their respective weights 28 func WeightedOperations( 29 registry codectypes.InterfaceRegistry, 30 appParams simtypes.AppParams, 31 cdc codec.JSONCodec, 32 txGen client.TxConfig, 33 ak types.AccountKeeper, 34 bk types.BankKeeper, 35 k keeper.Keeper, 36 sk types.StakingKeeper, 37 ) simulation.WeightedOperations { 38 var weightMsgUnjail int 39 appParams.GetOrGenerate(OpWeightMsgUnjail, &weightMsgUnjail, nil, func(_ *rand.Rand) { 40 weightMsgUnjail = DefaultWeightMsgUnjail 41 }) 42 43 return simulation.WeightedOperations{ 44 simulation.NewWeightedOperation( 45 weightMsgUnjail, 46 SimulateMsgUnjail(codec.NewProtoCodec(registry), txGen, ak, bk, k, sk), 47 ), 48 } 49 } 50 51 // SimulateMsgUnjail generates a MsgUnjail with random values 52 func SimulateMsgUnjail( 53 cdc *codec.ProtoCodec, 54 txGen client.TxConfig, 55 ak types.AccountKeeper, 56 bk types.BankKeeper, 57 k keeper.Keeper, 58 sk types.StakingKeeper, 59 ) simtypes.Operation { 60 return func( 61 r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, 62 accs []simtypes.Account, chainID string, 63 ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { 64 msgType := sdk.MsgTypeURL(&types.MsgUnjail{}) 65 66 allVals, err := sk.GetAllValidators(ctx) 67 if err != nil { 68 return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to get all validators"), nil, err 69 } 70 71 validator, ok := testutil.RandSliceElem(r, allVals) 72 if !ok { 73 return simtypes.NoOpMsg(types.ModuleName, msgType, "validator is not ok"), nil, nil // skip 74 } 75 76 bz, err := sk.ValidatorAddressCodec().StringToBytes(validator.GetOperator()) 77 if err != nil { 78 return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to convert validator address to bytes"), nil, err 79 } 80 81 simAccount, found := simtypes.FindAccount(accs, sdk.AccAddress(bz)) 82 if !found { 83 return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to find account"), nil, nil // skip 84 } 85 86 if !validator.IsJailed() { 87 // TODO: due to this condition this message is almost, if not always, skipped ! 88 return simtypes.NoOpMsg(types.ModuleName, msgType, "validator is not jailed"), nil, nil 89 } 90 91 consAddr, err := validator.GetConsAddr() 92 if err != nil { 93 return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to get validator consensus key"), nil, err 94 } 95 info, err := k.GetValidatorSigningInfo(ctx, consAddr) 96 if err != nil { 97 return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to find validator signing info"), nil, err // skip 98 } 99 100 selfDel, err := sk.Delegation(ctx, simAccount.Address, bz) 101 if err != nil { 102 return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to get self delegation"), nil, err 103 } 104 105 if selfDel == nil { 106 return simtypes.NoOpMsg(types.ModuleName, msgType, "self delegation is nil"), nil, nil // skip 107 } 108 109 account := ak.GetAccount(ctx, sdk.AccAddress(bz)) 110 spendable := bk.SpendableCoins(ctx, account.GetAddress()) 111 112 fees, err := simtypes.RandomFees(r, ctx, spendable) 113 if err != nil { 114 return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to generate fees"), nil, err 115 } 116 117 msg := types.NewMsgUnjail(validator.GetOperator()) 118 119 tx, err := simtestutil.GenSignedMockTx( 120 r, 121 txGen, 122 []sdk.Msg{msg}, 123 fees, 124 simtestutil.DefaultGenTxGas, 125 chainID, 126 []uint64{account.GetAccountNumber()}, 127 []uint64{account.GetSequence()}, 128 simAccount.PrivKey, 129 ) 130 if err != nil { 131 return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(msg), "unable to generate mock tx"), nil, err 132 } 133 134 _, res, err := app.SimDeliver(txGen.TxEncoder(), tx) 135 136 // result should fail if: 137 // - validator cannot be unjailed due to tombstone 138 // - validator is still in jailed period 139 // - self delegation too low 140 if info.Tombstoned || 141 ctx.BlockHeader().Time.Before(info.JailedUntil) || 142 validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) { 143 if res != nil && err == nil { 144 if info.Tombstoned { 145 return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator should not have been unjailed if validator tombstoned") 146 } 147 if ctx.BlockHeader().Time.Before(info.JailedUntil) { 148 return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator unjailed while validator still in jail period") 149 } 150 if validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) { 151 return simtypes.NewOperationMsg(msg, true, ""), nil, errors.New("validator unjailed even though self-delegation too low") 152 } 153 } 154 // msg failed as expected 155 return simtypes.NewOperationMsg(msg, false, ""), nil, nil 156 } 157 158 if err != nil { 159 return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, errors.New(res.Log) 160 } 161 162 return simtypes.NewOperationMsg(msg, true, ""), nil, nil 163 } 164 }