Skip to content

Commit 02ecb9e

Browse files
committed
add sim SimulateMsgAggregateExchangeRatePrevote
1 parent ba4adb4 commit 02ecb9e

File tree

6 files changed

+390
-0
lines changed

6 files changed

+390
-0
lines changed

app/app.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,7 @@ func New(
738738
params.NewAppModule(app.ParamsKeeper),
739739
evidence.NewAppModule(app.EvidenceKeeper),
740740
wasm.NewAppModule(appCodec, &app.wasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
741+
oracle.NewAppModule(appCodec, app.OracleKeeper, app.AccountKeeper, app.BankKeeper),
741742
ibc.NewAppModule(app.IBCKeeper),
742743
transferModule,
743744
)

x/oracle/module.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"math/rand"
78

89
"github.com/cosmos/cosmos-sdk/client"
910
"github.com/cosmos/cosmos-sdk/codec"
@@ -18,6 +19,7 @@ import (
1819

1920
"github.com/CosmosContracts/juno/v11/x/oracle/client/cli"
2021
"github.com/CosmosContracts/juno/v11/x/oracle/keeper"
22+
"github.com/CosmosContracts/juno/v11/x/oracle/simulation"
2123
"github.com/CosmosContracts/juno/v11/x/oracle/types"
2224
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
2325
)
@@ -180,8 +182,30 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val
180182
return []abci.ValidatorUpdate{}
181183
}
182184

185+
// GenerateGenesisState creates a randomized GenState of the distribution module.
186+
func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
187+
simulation.RandomizedGenState(simState)
188+
}
189+
190+
// WeightedOperations returns the all the gravity module operations with their respective weights.
191+
func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
192+
return simulation.WeightedOperations(
193+
&simState, am.accountKeeper, am.bankKeeper, am.keeper,
194+
)
195+
}
196+
183197
// ProposalContents returns all the oracle content functions used to
184198
// simulate governance proposals.
185199
func (am AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent {
186200
return nil
187201
}
202+
203+
// RandomizedParams creates randomized oracle param changes for the simulator.
204+
func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
205+
return simulation.ParamChanges(r)
206+
}
207+
208+
// RegisterStoreDecoder registers a decoder for oracle module's types
209+
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
210+
sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc)
211+
}

x/oracle/simulation/decoder.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package simulation
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
7+
"github.com/CosmosContracts/juno/v11/x/oracle/types"
8+
gogotypes "github.com/gogo/protobuf/types"
9+
10+
"github.com/cosmos/cosmos-sdk/codec"
11+
sdk "github.com/cosmos/cosmos-sdk/types"
12+
"github.com/cosmos/cosmos-sdk/types/kv"
13+
)
14+
15+
func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string {
16+
return func(kvA, kvB kv.Pair) string {
17+
switch {
18+
case bytes.Equal(kvA.Key[:1], types.KeyPrefixExchangeRate):
19+
var exchangeRateA, exchangeRateB sdk.DecProto
20+
cdc.MustUnmarshal(kvA.Value, &exchangeRateA)
21+
cdc.MustUnmarshal(kvB.Value, &exchangeRateB)
22+
return fmt.Sprintf("%v\n%v", exchangeRateA, exchangeRateB)
23+
24+
case bytes.Equal(kvA.Key[:1], types.KeyPrefixFeederDelegation):
25+
return fmt.Sprintf("%v\n%v", sdk.AccAddress(kvA.Value), sdk.AccAddress(kvB.Value))
26+
27+
case bytes.Equal(kvA.Key[:1], types.KeyPrefixMissCounter):
28+
var counterA, counterB gogotypes.UInt64Value
29+
cdc.MustUnmarshal(kvA.Value, &counterA)
30+
cdc.MustUnmarshal(kvB.Value, &counterB)
31+
return fmt.Sprintf("%v\n%v", counterA.Value, counterB.Value)
32+
33+
case bytes.Equal(kvA.Key[:1], types.KeyPrefixAggregateExchangeRatePrevote):
34+
var prevoteA, prevoteB types.AggregateExchangeRatePrevote
35+
cdc.MustUnmarshal(kvA.Value, &prevoteA)
36+
cdc.MustUnmarshal(kvB.Value, &prevoteB)
37+
return fmt.Sprintf("%v\n%v", prevoteA, prevoteB)
38+
39+
case bytes.Equal(kvA.Key[:1], types.KeyPrefixAggregateExchangeRateVote):
40+
var voteA, voteB types.AggregateExchangeRateVote
41+
cdc.MustUnmarshal(kvA.Value, &voteA)
42+
cdc.MustUnmarshal(kvB.Value, &voteB)
43+
return fmt.Sprintf("%v\n%v", voteA, voteB)
44+
45+
default:
46+
panic(fmt.Sprintf("invalid oracle key prefix %X", kvA.Key[:1]))
47+
}
48+
}
49+
}

x/oracle/simulation/genesis.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package simulation
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"math/rand"
7+
8+
"github.com/CosmosContracts/juno/v11/x/oracle/types"
9+
sdk "github.com/cosmos/cosmos-sdk/types"
10+
"github.com/cosmos/cosmos-sdk/types/module"
11+
)
12+
13+
const (
14+
votePeriodKey = "vote_period"
15+
voteThresholdKey = "vote_threshold"
16+
rewardBandKey = "reward_band"
17+
rewardDistributionWindowKey = "reward_distribution_window"
18+
slashFractionKey = "slash_fraction"
19+
slashWindowKey = "slash_window"
20+
minValidPerWindowKey = "min_valid_per_window"
21+
)
22+
23+
// GenVotePeriod produces a randomized VotePeriod in the range of [5, 100]
24+
func GenVotePeriod(r *rand.Rand) uint64 {
25+
return uint64(5 + r.Intn(100))
26+
}
27+
28+
// GenVoteThreshold produces a randomized VoteThreshold in the range of [0.333, 0.666]
29+
func GenVoteThreshold(r *rand.Rand) sdk.Dec {
30+
return sdk.NewDecWithPrec(333, 3).Add(sdk.NewDecWithPrec(int64(r.Intn(333)), 3))
31+
}
32+
33+
// GenRewardBand produces a randomized RewardBand in the range of [0.000, 0.100]
34+
func GenRewardBand(r *rand.Rand) sdk.Dec {
35+
return sdk.ZeroDec().Add(sdk.NewDecWithPrec(int64(r.Intn(100)), 3))
36+
}
37+
38+
// GenRewardDistributionWindow produces a randomized RewardDistributionWindow in the range of [100, 100000]
39+
func GenRewardDistributionWindow(r *rand.Rand) uint64 {
40+
return uint64(100 + r.Intn(100000))
41+
}
42+
43+
// GenSlashFraction produces a randomized SlashFraction in the range of [0.000, 0.100]
44+
func GenSlashFraction(r *rand.Rand) sdk.Dec {
45+
return sdk.ZeroDec().Add(sdk.NewDecWithPrec(int64(r.Intn(100)), 3))
46+
}
47+
48+
// GenSlashWindow produces a randomized SlashWindow in the range of [100, 100000]
49+
func GenSlashWindow(r *rand.Rand) uint64 {
50+
return uint64(100 + r.Intn(100000))
51+
}
52+
53+
// GenMinValidPerWindow produces a randomized MinValidPerWindow in the range of [0, 0.500]
54+
func GenMinValidPerWindow(r *rand.Rand) sdk.Dec {
55+
return sdk.ZeroDec().Add(sdk.NewDecWithPrec(int64(r.Intn(500)), 3))
56+
}
57+
58+
// RandomizedGenState generates a random GenesisState for oracle
59+
func RandomizedGenState(simState *module.SimulationState) {
60+
var votePeriod uint64
61+
simState.AppParams.GetOrGenerate(
62+
simState.Cdc, votePeriodKey, &votePeriod, simState.Rand,
63+
func(r *rand.Rand) { votePeriod = GenVotePeriod(r) },
64+
)
65+
66+
var voteThreshold sdk.Dec
67+
simState.AppParams.GetOrGenerate(
68+
simState.Cdc, voteThresholdKey, &voteThreshold, simState.Rand,
69+
func(r *rand.Rand) { voteThreshold = GenVoteThreshold(r) },
70+
)
71+
72+
var rewardBand sdk.Dec
73+
simState.AppParams.GetOrGenerate(
74+
simState.Cdc, rewardBandKey, &rewardBand, simState.Rand,
75+
func(r *rand.Rand) { rewardBand = GenRewardBand(r) },
76+
)
77+
78+
var rewardDistributionWindow uint64
79+
simState.AppParams.GetOrGenerate(
80+
simState.Cdc, rewardDistributionWindowKey, &rewardDistributionWindow, simState.Rand,
81+
func(r *rand.Rand) { rewardDistributionWindow = GenRewardDistributionWindow(r) },
82+
)
83+
84+
var slashFraction sdk.Dec
85+
simState.AppParams.GetOrGenerate(
86+
simState.Cdc, slashFractionKey, &slashFraction, simState.Rand,
87+
func(r *rand.Rand) { slashFraction = GenSlashFraction(r) },
88+
)
89+
90+
var slashWindow uint64
91+
simState.AppParams.GetOrGenerate(
92+
simState.Cdc, slashWindowKey, &slashWindow, simState.Rand,
93+
func(r *rand.Rand) { slashWindow = GenSlashWindow(r) },
94+
)
95+
96+
var minValidPerWindow sdk.Dec
97+
simState.AppParams.GetOrGenerate(
98+
simState.Cdc, minValidPerWindowKey, &minValidPerWindow, simState.Rand,
99+
func(r *rand.Rand) { minValidPerWindow = GenMinValidPerWindow(r) },
100+
)
101+
102+
oracleGenesis := types.NewGenesisState(
103+
types.Params{
104+
VotePeriod: votePeriod,
105+
VoteThreshold: voteThreshold,
106+
RewardBand: rewardBand,
107+
RewardDistributionWindow: rewardDistributionWindow,
108+
AcceptList: types.DenomList{
109+
{SymbolDenom: types.JunoSymbol, BaseDenom: types.JunoDenom},
110+
},
111+
SlashFraction: slashFraction,
112+
SlashWindow: slashWindow,
113+
MinValidPerWindow: minValidPerWindow,
114+
},
115+
[]types.ExchangeRateTuple{},
116+
[]types.FeederDelegation{},
117+
[]types.MissCounter{},
118+
[]types.AggregateExchangeRatePrevote{},
119+
[]types.AggregateExchangeRateVote{},
120+
)
121+
122+
bz, err := json.MarshalIndent(&oracleGenesis.Params, "", " ")
123+
if err != nil {
124+
panic(err)
125+
}
126+
fmt.Printf("Selected randomly generated oracle parameters:\n%s\n", bz)
127+
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(oracleGenesis)
128+
}

x/oracle/simulation/operations.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
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

Comments
 (0)