github.com/Finschia/finschia-sdk@v0.49.1/x/distribution/simulation/operations.go (about) 1 package simulation 2 3 import ( 4 "fmt" 5 "math/rand" 6 7 "github.com/Finschia/finschia-sdk/baseapp" 8 "github.com/Finschia/finschia-sdk/codec" 9 simappparams "github.com/Finschia/finschia-sdk/simapp/params" 10 sdk "github.com/Finschia/finschia-sdk/types" 11 simtypes "github.com/Finschia/finschia-sdk/types/simulation" 12 "github.com/Finschia/finschia-sdk/x/distribution/keeper" 13 "github.com/Finschia/finschia-sdk/x/distribution/types" 14 "github.com/Finschia/finschia-sdk/x/simulation" 15 stakingkeeper "github.com/Finschia/finschia-sdk/x/staking/keeper" 16 ) 17 18 // Simulation operation weights constants 19 const ( 20 OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address" 21 OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward" 22 OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission" 23 OpWeightMsgFundCommunityPool = "op_weight_msg_fund_community_pool" 24 ) 25 26 // WeightedOperations returns all the operations from the module with their respective weights 27 func WeightedOperations(appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk types.StakingKeeper) simulation.WeightedOperations { 28 var weightMsgSetWithdrawAddress int 29 appParams.GetOrGenerate(cdc, OpWeightMsgSetWithdrawAddress, &weightMsgSetWithdrawAddress, nil, 30 func(_ *rand.Rand) { 31 weightMsgSetWithdrawAddress = simappparams.DefaultWeightMsgSetWithdrawAddress 32 }, 33 ) 34 35 var weightMsgWithdrawDelegationReward int 36 appParams.GetOrGenerate(cdc, OpWeightMsgWithdrawDelegationReward, &weightMsgWithdrawDelegationReward, nil, 37 func(_ *rand.Rand) { 38 weightMsgWithdrawDelegationReward = simappparams.DefaultWeightMsgWithdrawDelegationReward 39 }, 40 ) 41 42 var weightMsgWithdrawValidatorCommission int 43 appParams.GetOrGenerate(cdc, OpWeightMsgWithdrawValidatorCommission, &weightMsgWithdrawValidatorCommission, nil, 44 func(_ *rand.Rand) { 45 weightMsgWithdrawValidatorCommission = simappparams.DefaultWeightMsgWithdrawValidatorCommission 46 }, 47 ) 48 49 var weightMsgFundCommunityPool int 50 appParams.GetOrGenerate(cdc, OpWeightMsgFundCommunityPool, &weightMsgFundCommunityPool, nil, 51 func(_ *rand.Rand) { 52 weightMsgFundCommunityPool = simappparams.DefaultWeightMsgFundCommunityPool 53 }, 54 ) 55 56 stakeKeeper := sk.(stakingkeeper.Keeper) 57 58 return simulation.WeightedOperations{ 59 simulation.NewWeightedOperation( 60 weightMsgSetWithdrawAddress, 61 SimulateMsgSetWithdrawAddress(ak, bk, k), 62 ), 63 simulation.NewWeightedOperation( 64 weightMsgWithdrawDelegationReward, 65 SimulateMsgWithdrawDelegatorReward(ak, bk, k, stakeKeeper), 66 ), 67 simulation.NewWeightedOperation( 68 weightMsgWithdrawValidatorCommission, 69 SimulateMsgWithdrawValidatorCommission(ak, bk, k, stakeKeeper), 70 ), 71 simulation.NewWeightedOperation( 72 weightMsgFundCommunityPool, 73 SimulateMsgFundCommunityPool(ak, bk, k, stakeKeeper), 74 ), 75 } 76 } 77 78 // SimulateMsgSetWithdrawAddress generates a MsgSetWithdrawAddress with random values. 79 func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { 80 return func( 81 r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, 82 ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { 83 if !k.GetWithdrawAddrEnabled(ctx) { 84 return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSetWithdrawAddress, "withdrawal is not enabled"), nil, nil 85 } 86 87 simAccount, _ := simtypes.RandomAcc(r, accs) 88 simToAccount, _ := simtypes.RandomAcc(r, accs) 89 90 account := ak.GetAccount(ctx, simAccount.Address) 91 spendable := bk.SpendableCoins(ctx, account.GetAddress()) 92 93 msg := types.NewMsgSetWithdrawAddress(simAccount.Address, simToAccount.Address) 94 95 txCtx := simulation.OperationInput{ 96 R: r, 97 App: app, 98 TxGen: simappparams.MakeTestEncodingConfig().TxConfig, 99 Cdc: nil, 100 Msg: msg, 101 MsgType: msg.Type(), 102 Context: ctx, 103 SimAccount: simAccount, 104 AccountKeeper: ak, 105 Bankkeeper: bk, 106 ModuleName: types.ModuleName, 107 CoinsSpentInMsg: spendable, 108 } 109 110 return simulation.GenAndDeliverTxWithRandFees(txCtx) 111 } 112 } 113 114 // SimulateMsgWithdrawDelegatorReward generates a MsgWithdrawDelegatorReward with random values. 115 func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simtypes.Operation { 116 return func( 117 r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, 118 ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { 119 simAccount, _ := simtypes.RandomAcc(r, accs) 120 delegations := sk.GetAllDelegatorDelegations(ctx, simAccount.Address) 121 if len(delegations) == 0 { 122 return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawDelegatorReward, "number of delegators equal 0"), nil, nil 123 } 124 125 delegation := delegations[r.Intn(len(delegations))] 126 127 validator := sk.Validator(ctx, delegation.GetValidatorAddr()) 128 if validator == nil { 129 return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawDelegatorReward, "validator is nil"), nil, fmt.Errorf("validator %s not found", delegation.GetValidatorAddr()) 130 } 131 132 account := ak.GetAccount(ctx, simAccount.Address) 133 spendable := bk.SpendableCoins(ctx, account.GetAddress()) 134 135 msg := types.NewMsgWithdrawDelegatorReward(simAccount.Address, validator.GetOperator()) 136 137 txCtx := simulation.OperationInput{ 138 R: r, 139 App: app, 140 TxGen: simappparams.MakeTestEncodingConfig().TxConfig, 141 Cdc: nil, 142 Msg: msg, 143 MsgType: msg.Type(), 144 Context: ctx, 145 SimAccount: simAccount, 146 AccountKeeper: ak, 147 Bankkeeper: bk, 148 ModuleName: types.ModuleName, 149 CoinsSpentInMsg: spendable, 150 } 151 152 return simulation.GenAndDeliverTxWithRandFees(txCtx) 153 } 154 } 155 156 // SimulateMsgWithdrawValidatorCommission generates a MsgWithdrawValidatorCommission with random values. 157 func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simtypes.Operation { 158 return func( 159 r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, 160 ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { 161 validator, ok := stakingkeeper.RandomValidator(r, sk, ctx) 162 if !ok { 163 return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawValidatorCommission, "random validator is not ok"), nil, nil 164 } 165 166 commission := k.GetValidatorAccumulatedCommission(ctx, validator.GetOperator()) 167 if commission.Commission.IsZero() { 168 return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawValidatorCommission, "validator commission is zero"), nil, nil 169 } 170 171 simAccount, found := simtypes.FindAccount(accs, sdk.AccAddress(validator.GetOperator())) 172 if !found { 173 return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawValidatorCommission, "could not find account"), nil, fmt.Errorf("validator %s not found", validator.GetOperator()) 174 } 175 176 account := ak.GetAccount(ctx, simAccount.Address) 177 spendable := bk.SpendableCoins(ctx, account.GetAddress()) 178 179 msg := types.NewMsgWithdrawValidatorCommission(validator.GetOperator()) 180 181 txCtx := simulation.OperationInput{ 182 R: r, 183 App: app, 184 TxGen: simappparams.MakeTestEncodingConfig().TxConfig, 185 Cdc: nil, 186 Msg: msg, 187 MsgType: msg.Type(), 188 Context: ctx, 189 SimAccount: simAccount, 190 AccountKeeper: ak, 191 Bankkeeper: bk, 192 ModuleName: types.ModuleName, 193 CoinsSpentInMsg: spendable, 194 } 195 196 return simulation.GenAndDeliverTxWithRandFees(txCtx) 197 } 198 } 199 200 // SimulateMsgFundCommunityPool simulates MsgFundCommunityPool execution where 201 // a random account sends a random amount of its funds to the community pool. 202 func SimulateMsgFundCommunityPool(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simtypes.Operation { 203 return func( 204 r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, 205 ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { 206 funder, _ := simtypes.RandomAcc(r, accs) 207 208 account := ak.GetAccount(ctx, funder.Address) 209 spendable := bk.SpendableCoins(ctx, account.GetAddress()) 210 211 fundAmount := simtypes.RandSubsetCoins(r, spendable) 212 if fundAmount.Empty() { 213 return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgFundCommunityPool, "fund amount is empty"), nil, nil 214 } 215 216 var ( 217 fees sdk.Coins 218 err error 219 ) 220 221 coins, hasNeg := spendable.SafeSub(fundAmount) 222 if !hasNeg { 223 fees, err = simtypes.RandomFees(r, ctx, coins) 224 if err != nil { 225 return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgFundCommunityPool, "unable to generate fees"), nil, err 226 } 227 } 228 229 msg := types.NewMsgFundCommunityPool(fundAmount, funder.Address) 230 231 txCtx := simulation.OperationInput{ 232 R: r, 233 App: app, 234 TxGen: simappparams.MakeTestEncodingConfig().TxConfig, 235 Cdc: nil, 236 Msg: msg, 237 MsgType: msg.Type(), 238 Context: ctx, 239 SimAccount: funder, 240 AccountKeeper: ak, 241 ModuleName: types.ModuleName, 242 } 243 244 return simulation.GenAndDeliverTx(txCtx, fees) 245 } 246 }