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  }