cosmos-sdk/x/distribution/simulation/operations.go
cool-developer 372a8f194e
refactor: remove simapp from x/staking module (#13101)
## Description

Closes: #13099 



---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
2022-08-31 14:50:22 +00:00

257 lines
9.4 KiB
Go

package simulation
import (
"fmt"
"math/rand"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/cosmos/cosmos-sdk/x/distribution/keeper"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/cosmos/cosmos-sdk/x/simulation"
)
// Simulation operation weights constants
//
//nolint:gosec // these are not hardcoded credentials.
const (
OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address"
OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward"
OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission"
OpWeightMsgFundCommunityPool = "op_weight_msg_fund_community_pool"
DefaultWeightMsgSetWithdrawAddress int = 50
DefaultWeightMsgWithdrawDelegationReward int = 50
DefaultWeightMsgWithdrawValidatorCommission int = 50
DefaultWeightMsgFundCommunityPool int = 50
)
// WeightedOperations returns all the operations from the module with their respective weights
func WeightedOperations(appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk types.StakingKeeper) simulation.WeightedOperations {
var weightMsgSetWithdrawAddress int
appParams.GetOrGenerate(cdc, OpWeightMsgSetWithdrawAddress, &weightMsgSetWithdrawAddress, nil,
func(_ *rand.Rand) {
weightMsgSetWithdrawAddress = DefaultWeightMsgSetWithdrawAddress
},
)
var weightMsgWithdrawDelegationReward int
appParams.GetOrGenerate(cdc, OpWeightMsgWithdrawDelegationReward, &weightMsgWithdrawDelegationReward, nil,
func(_ *rand.Rand) {
weightMsgWithdrawDelegationReward = DefaultWeightMsgWithdrawDelegationReward
},
)
var weightMsgWithdrawValidatorCommission int
appParams.GetOrGenerate(cdc, OpWeightMsgWithdrawValidatorCommission, &weightMsgWithdrawValidatorCommission, nil,
func(_ *rand.Rand) {
weightMsgWithdrawValidatorCommission = DefaultWeightMsgWithdrawValidatorCommission
},
)
var weightMsgFundCommunityPool int
appParams.GetOrGenerate(cdc, OpWeightMsgFundCommunityPool, &weightMsgFundCommunityPool, nil,
func(_ *rand.Rand) {
weightMsgFundCommunityPool = DefaultWeightMsgFundCommunityPool
},
)
interfaceRegistry := codectypes.NewInterfaceRegistry()
txConfig := tx.NewTxConfig(codec.NewProtoCodec(interfaceRegistry), tx.DefaultSignModes)
return simulation.WeightedOperations{
simulation.NewWeightedOperation(
weightMsgSetWithdrawAddress,
SimulateMsgSetWithdrawAddress(txConfig, ak, bk, k),
),
simulation.NewWeightedOperation(
weightMsgWithdrawDelegationReward,
SimulateMsgWithdrawDelegatorReward(txConfig, ak, bk, k, sk),
),
simulation.NewWeightedOperation(
weightMsgWithdrawValidatorCommission,
SimulateMsgWithdrawValidatorCommission(txConfig, ak, bk, k, sk),
),
simulation.NewWeightedOperation(
weightMsgFundCommunityPool,
SimulateMsgFundCommunityPool(txConfig, ak, bk, k, sk),
),
}
}
// SimulateMsgSetWithdrawAddress generates a MsgSetWithdrawAddress with random values.
func SimulateMsgSetWithdrawAddress(txConfig client.TxConfig, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
if !k.GetWithdrawAddrEnabled(ctx) {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSetWithdrawAddress, "withdrawal is not enabled"), nil, nil
}
simAccount, _ := simtypes.RandomAcc(r, accs)
simToAccount, _ := simtypes.RandomAcc(r, accs)
account := ak.GetAccount(ctx, simAccount.Address)
spendable := bk.SpendableCoins(ctx, account.GetAddress())
msg := types.NewMsgSetWithdrawAddress(simAccount.Address, simToAccount.Address)
txCtx := simulation.OperationInput{
R: r,
App: app,
TxGen: txConfig,
Cdc: nil,
Msg: msg,
MsgType: msg.Type(),
Context: ctx,
SimAccount: simAccount,
AccountKeeper: ak,
Bankkeeper: bk,
ModuleName: types.ModuleName,
CoinsSpentInMsg: spendable,
}
return simulation.GenAndDeliverTxWithRandFees(txCtx)
}
}
// SimulateMsgWithdrawDelegatorReward generates a MsgWithdrawDelegatorReward with random values.
func SimulateMsgWithdrawDelegatorReward(txConfig client.TxConfig, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk types.StakingKeeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
simAccount, _ := simtypes.RandomAcc(r, accs)
delegations := sk.GetAllDelegatorDelegations(ctx, simAccount.Address)
if len(delegations) == 0 {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawDelegatorReward, "number of delegators equal 0"), nil, nil
}
delegation := delegations[r.Intn(len(delegations))]
validator := sk.Validator(ctx, delegation.GetValidatorAddr())
if validator == nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawDelegatorReward, "validator is nil"), nil, fmt.Errorf("validator %s not found", delegation.GetValidatorAddr())
}
account := ak.GetAccount(ctx, simAccount.Address)
spendable := bk.SpendableCoins(ctx, account.GetAddress())
msg := types.NewMsgWithdrawDelegatorReward(simAccount.Address, validator.GetOperator())
txCtx := simulation.OperationInput{
R: r,
App: app,
TxGen: txConfig,
Cdc: nil,
Msg: msg,
MsgType: msg.Type(),
Context: ctx,
SimAccount: simAccount,
AccountKeeper: ak,
Bankkeeper: bk,
ModuleName: types.ModuleName,
CoinsSpentInMsg: spendable,
}
return simulation.GenAndDeliverTxWithRandFees(txCtx)
}
}
// SimulateMsgWithdrawValidatorCommission generates a MsgWithdrawValidatorCommission with random values.
func SimulateMsgWithdrawValidatorCommission(txConfig client.TxConfig, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk types.StakingKeeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
validator, ok := testutil.RandSliceElem(r, sk.GetAllValidators(ctx))
if !ok {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawValidatorCommission, "random validator is not ok"), nil, nil
}
commission := k.GetValidatorAccumulatedCommission(ctx, validator.GetOperator())
if commission.Commission.IsZero() {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawValidatorCommission, "validator commission is zero"), nil, nil
}
simAccount, found := simtypes.FindAccount(accs, sdk.AccAddress(validator.GetOperator()))
if !found {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgWithdrawValidatorCommission, "could not find account"), nil, fmt.Errorf("validator %s not found", validator.GetOperator())
}
account := ak.GetAccount(ctx, simAccount.Address)
spendable := bk.SpendableCoins(ctx, account.GetAddress())
msg := types.NewMsgWithdrawValidatorCommission(validator.GetOperator())
txCtx := simulation.OperationInput{
R: r,
App: app,
TxGen: txConfig,
Cdc: nil,
Msg: msg,
MsgType: msg.Type(),
Context: ctx,
SimAccount: simAccount,
AccountKeeper: ak,
Bankkeeper: bk,
ModuleName: types.ModuleName,
CoinsSpentInMsg: spendable,
}
return simulation.GenAndDeliverTxWithRandFees(txCtx)
}
}
// SimulateMsgFundCommunityPool simulates MsgFundCommunityPool execution where
// a random account sends a random amount of its funds to the community pool.
func SimulateMsgFundCommunityPool(txConfig client.TxConfig, ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, sk types.StakingKeeper) simtypes.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
funder, _ := simtypes.RandomAcc(r, accs)
account := ak.GetAccount(ctx, funder.Address)
spendable := bk.SpendableCoins(ctx, account.GetAddress())
fundAmount := simtypes.RandSubsetCoins(r, spendable)
if fundAmount.Empty() {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgFundCommunityPool, "fund amount is empty"), nil, nil
}
var (
fees sdk.Coins
err error
)
coins, hasNeg := spendable.SafeSub(fundAmount...)
if !hasNeg {
fees, err = simtypes.RandomFees(r, ctx, coins)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgFundCommunityPool, "unable to generate fees"), nil, err
}
}
msg := types.NewMsgFundCommunityPool(fundAmount, funder.Address)
txCtx := simulation.OperationInput{
R: r,
App: app,
TxGen: txConfig,
Cdc: nil,
Msg: msg,
MsgType: msg.Type(),
Context: ctx,
SimAccount: funder,
AccountKeeper: ak,
ModuleName: types.ModuleName,
}
return simulation.GenAndDeliverTx(txCtx, fees)
}
}