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  }