|
| 1 | +package simulation |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "math/rand" |
| 6 | + "sort" |
| 7 | + "strings" |
| 8 | + |
| 9 | + "github.com/CosmosContracts/juno/v11/x/oracle/keeper" |
| 10 | + "github.com/CosmosContracts/juno/v11/x/oracle/types" |
| 11 | + "github.com/cosmos/cosmos-sdk/baseapp" |
| 12 | + "github.com/cosmos/cosmos-sdk/codec" |
| 13 | + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" |
| 14 | + sdk "github.com/cosmos/cosmos-sdk/types" |
| 15 | + "github.com/cosmos/cosmos-sdk/types/module" |
| 16 | + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" |
| 17 | + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" |
| 18 | + "github.com/cosmos/cosmos-sdk/x/simulation" |
| 19 | +) |
| 20 | + |
| 21 | +// Simulation operation weights constants |
| 22 | +// |
| 23 | +//nolint:gosec |
| 24 | +const ( |
| 25 | + OpWeightMsgAggregateExchangeRatePrevote = "op_weight_msg_exchange_rate_aggregate_prevote" |
| 26 | + |
| 27 | + salt = "89b8164ca0b4b8703ae9ab25962f3dd6d1de5d656f5442971a93b2ca7893f654" |
| 28 | +) |
| 29 | + |
| 30 | +var ( |
| 31 | + acceptList = []string{types.JunoSymbol, types.USDDenom} |
| 32 | + umeePrice = sdk.MustNewDecFromStr("25.71") |
| 33 | +) |
| 34 | + |
| 35 | +// GenerateExchangeRatesString generates a canonical string representation of |
| 36 | +// the aggregated exchange rates. |
| 37 | +func GenerateExchangeRatesString(prices map[string]sdk.Dec) string { |
| 38 | + exchangeRates := make([]string, len(prices)) |
| 39 | + i := 0 |
| 40 | + |
| 41 | + // aggregate exchange rates as "<base>:<price>" |
| 42 | + for base, avgPrice := range prices { |
| 43 | + exchangeRates[i] = fmt.Sprintf("%s:%s", base, avgPrice.String()) |
| 44 | + i++ |
| 45 | + } |
| 46 | + |
| 47 | + sort.Strings(exchangeRates) |
| 48 | + |
| 49 | + return strings.Join(exchangeRates, ",") |
| 50 | +} |
| 51 | + |
| 52 | +func WeightedOperations( |
| 53 | + simstate *module.SimulationState, |
| 54 | + ak types.AccountKeeper, |
| 55 | + bk bankkeeper.Keeper, |
| 56 | + k keeper.Keeper, |
| 57 | +) simulation.WeightedOperations { |
| 58 | + var ( |
| 59 | + weightMsgAggregateExchangeRatePrevote int |
| 60 | + voteHashMap = make(map[string]string) |
| 61 | + ) |
| 62 | + |
| 63 | + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgAggregateExchangeRatePrevote, &weightMsgAggregateExchangeRatePrevote, nil, |
| 64 | + func(_ *rand.Rand) { |
| 65 | + weightMsgAggregateExchangeRatePrevote = simappparams.DefaultWeightMsgSend * 2 |
| 66 | + }, |
| 67 | + ) |
| 68 | + |
| 69 | + return simulation.WeightedOperations{ |
| 70 | + simulation.NewWeightedOperation( |
| 71 | + weightMsgAggregateExchangeRatePrevote, |
| 72 | + SimulateMsgAggregateExchangeRatePrevote(ak, bk, k, voteHashMap), |
| 73 | + ), |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +// SimulateMsgAggregateExchangeRatePrevote generates a MsgAggregateExchangeRatePrevote with random values. |
| 78 | +func SimulateMsgAggregateExchangeRatePrevote( |
| 79 | + ak types.AccountKeeper, |
| 80 | + bk bankkeeper.Keeper, |
| 81 | + k keeper.Keeper, |
| 82 | + voteHashMap map[string]string, |
| 83 | +) simtypes.Operation { |
| 84 | + return func( |
| 85 | + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, |
| 86 | + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { |
| 87 | + simAccount := accs[1] // , _ := simtypes.RandomAcc(r, accs) |
| 88 | + address := sdk.ValAddress(simAccount.Address) |
| 89 | + noop := func(comment string) simtypes.OperationMsg { |
| 90 | + return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(new(types.MsgAggregateExchangeRatePrevote)), comment) |
| 91 | + } |
| 92 | + |
| 93 | + // ensure the validator exists |
| 94 | + val := k.StakingKeeper.Validator(ctx, address) |
| 95 | + if val == nil || !val.IsBonded() { |
| 96 | + return noop("unable to find validator"), nil, nil |
| 97 | + } |
| 98 | + |
| 99 | + // check for an existing prevote |
| 100 | + _, err := k.GetAggregateExchangeRatePrevote(ctx, address) |
| 101 | + if err == nil { |
| 102 | + return noop("prevote already exists for this validator"), nil, nil |
| 103 | + } |
| 104 | + |
| 105 | + prices := make(map[string]sdk.Dec, len(acceptList)) |
| 106 | + for _, denom := range acceptList { |
| 107 | + prices[denom] = umeePrice.Add(simtypes.RandomDecAmount(r, sdk.NewDec(1))) |
| 108 | + } |
| 109 | + |
| 110 | + exchangeRatesStr := GenerateExchangeRatesString(prices) |
| 111 | + voteHash := types.GetAggregateVoteHash(salt, exchangeRatesStr, address) |
| 112 | + feederAddr, _ := k.GetFeederDelegation(ctx, address) |
| 113 | + feederSimAccount, _ := simtypes.FindAccount(accs, feederAddr) |
| 114 | + msg := types.NewMsgAggregateExchangeRatePrevote(voteHash, feederAddr, address) |
| 115 | + voteHashMap[address.String()] = exchangeRatesStr |
| 116 | + |
| 117 | + return deliver(r, app, ctx, ak, bk, feederSimAccount, msg, nil) |
| 118 | + } |
| 119 | +} |
| 120 | + |
| 121 | +func deliver(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, ak simulation.AccountKeeper, |
| 122 | + bk bankkeeper.Keeper, from simtypes.Account, msg sdk.Msg, coins sdk.Coins, |
| 123 | +) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { |
| 124 | + cfg := simappparams.MakeTestEncodingConfig() |
| 125 | + txCtx := simulation.OperationInput{ |
| 126 | + R: r, |
| 127 | + App: app, |
| 128 | + TxGen: cfg.TxConfig, |
| 129 | + Cdc: cfg.Marshaler.(*codec.ProtoCodec), |
| 130 | + Msg: msg, |
| 131 | + MsgType: sdk.MsgTypeURL(msg), |
| 132 | + Context: ctx, |
| 133 | + SimAccount: from, |
| 134 | + AccountKeeper: ak, |
| 135 | + Bankkeeper: bk, |
| 136 | + ModuleName: types.ModuleName, |
| 137 | + CoinsSpentInMsg: coins, |
| 138 | + } |
| 139 | + |
| 140 | + return simulation.GenAndDeliverTxWithRandFees(txCtx) |
| 141 | +} |
0 commit comments