-
Notifications
You must be signed in to change notification settings - Fork 339
/
operations.go
130 lines (108 loc) · 4.27 KB
/
operations.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package simulation
import (
"math/rand"
"time"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp/helpers"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/simulation"
appparams "github.com/kava-labs/kava/app/params"
"github.com/kava-labs/kava/x/pricefeed/keeper"
"github.com/kava-labs/kava/x/pricefeed/types"
)
// Simulation operation weights constants
const (
OpWeightMsgUpdatePrices = "op_weight_msg_update_prices"
)
// WeightedOperations returns all the operations from the module with their respective weights
func WeightedOperations(
appParams simulation.AppParams, cdc *codec.Codec, ak auth.AccountKeeper, k keeper.Keeper,
) simulation.WeightedOperations {
var weightMsgUpdatePrices int
// var numBlocks int
appParams.GetOrGenerate(cdc, OpWeightMsgUpdatePrices, &weightMsgUpdatePrices, nil,
func(_ *rand.Rand) {
weightMsgUpdatePrices = appparams.DefaultWeightMsgUpdatePrices
},
)
return simulation.WeightedOperations{
simulation.NewWeightedOperation(
weightMsgUpdatePrices,
SimulateMsgUpdatePrices(ak, k, 10000),
),
}
}
// SimulateMsgUpdatePrices updates the prices of various assets by randomly varying them based on current price
func SimulateMsgUpdatePrices(ak auth.AccountKeeper, keeper keeper.Keeper, blocks int) simulation.Operation {
// runs one at the start of each simulation
startingPrices := map[string]sdk.Dec{
"btc:usd": sdk.MustNewDecFromStr("7000"),
"bnb:usd": sdk.MustNewDecFromStr("15"),
"xrp:usd": sdk.MustNewDecFromStr("0.25"),
}
// creates the new price generator from starting prices - resets for each sim
priceGenerator := NewPriceGenerator(startingPrices)
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string,
) (simulation.OperationMsg, []simulation.FutureOperation, error) {
// walk prices to current block height, noop if already called for current height
priceGenerator.Step(r, ctx.BlockHeight())
randomMarket := pickRandomAsset(ctx, keeper, r)
marketID := randomMarket.MarketID
address := getRandomOracle(r, randomMarket)
oracle, found := simulation.FindAccount(accs, address)
if !found {
return simulation.NoOpMsg(types.ModuleName), nil, nil
}
oracleAcc := ak.GetAccount(ctx, oracle.Address)
if oracleAcc == nil {
return simulation.NoOpMsg(types.ModuleName), nil, nil
}
// get price for marketID and current block height set in Step
price := priceGenerator.GetCurrentPrice(marketID)
// get the expiry time based off the current time
expiry := getExpiryTime(ctx)
// now create the msg to post price
msg := types.NewMsgPostPrice(oracle.Address, marketID, price, expiry)
spendable := oracleAcc.SpendableCoins(ctx.BlockTime())
fees, err := simulation.RandomFees(r, ctx, spendable)
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
tx := helpers.GenTx(
[]sdk.Msg{msg},
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{oracleAcc.GetAccountNumber()},
[]uint64{oracleAcc.GetSequence()},
oracle.PrivKey,
)
_, result, err := app.Deliver(tx)
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
}
}
// getRandomOracle picks a random oracle from the list of oracles
func getRandomOracle(r *rand.Rand, market types.Market) sdk.AccAddress {
randomIndex := simulation.RandIntBetween(r, 0, len(market.Oracles))
return market.Oracles[randomIndex]
}
// pickRandomAsset picks a random asset out of the assets with equal probability
// it returns the Market which includes the base asset as one of its fields
func pickRandomAsset(ctx sdk.Context, keeper keeper.Keeper, r *rand.Rand) (market types.Market) {
// get the params
params := keeper.GetParams(ctx)
// now pick a random asset
randomIndex := simulation.RandIntBetween(r, 0, len(params.Markets))
return params.Markets[randomIndex]
}
// getExpiryTime gets a price expiry time by taking the current time and adding a delta to it
func getExpiryTime(ctx sdk.Context) (t time.Time) {
// need to use the blocktime from the context as the context generates random start time when running simulations
return ctx.BlockTime().Add(time.Second * 1000000)
}