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