Skip to content

Commit

Permalink
simulator: add gamm and tokenfactory messages (#2091)
Browse files Browse the repository at this point in the history
* initial push

* Update simulation/types/account.go

Co-authored-by: Dev Ojha <[email protected]>

* lint

* switch to RandomGenesisState

* no need for balance

* Update x/tokenfactory/simulation/sim_msgs.go

Co-authored-by: Dev Ojha <[email protected]>

* Fix merge conflict

* Update x/gamm/simulation/sim_msgs.go

Co-authored-by: Dev Ojha <[email protected]>

* switch to univ2 verbiage

* Update x/gamm/simulation/sim_msgs.go

Co-authored-by: Dev Ojha <[email protected]>

* address Dev comment

* Fix merge conflict

* name fix 2

* spelling

* add mint token factory denom

* update path from v7 to v10

* cap join pool to total pool liquidity

* remove test logs

* check if wallet has enough for pool creation fee

* Reduce token factory complexity

* Fix compilation issue

* Fix second error

* Some more updates

* Fix lint

* Move kludge to helper, fix lint

* Fix build

* Add log fix discussed in call

Co-authored-by: Dev Ojha <[email protected]>
Co-authored-by: Dev Ojha <[email protected]>
  • Loading branch information
3 people authored Jul 18, 2022
1 parent 8fe3fa7 commit 17ebcc8
Show file tree
Hide file tree
Showing 12 changed files with 324 additions and 38 deletions.
15 changes: 15 additions & 0 deletions osmoutils/coin_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,18 @@ func CoinsDenoms(coins sdk.Coins) []string {
}
return denoms
}

// MinCoins returns the minimum of each denom between both coins.
// For now it assumes they have the same denoms.
// TODO: Replace with method in SDK once we update our version
func MinCoins(coinsA sdk.Coins, coinsB sdk.Coins) sdk.Coins {
resCoins := sdk.Coins{}
for i, coin := range coinsA {
if coinsB[i].Amount.GT(coin.Amount) {
resCoins = append(resCoins, coin)
} else {
resCoins = append(resCoins, coinsB[i])
}
}
return resCoins
}
14 changes: 14 additions & 0 deletions osmoutils/iter_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package osmoutils

import "github.com/cosmos/cosmos-sdk/store"

func GatherAllKeysFromStore(storeObj store.KVStore) []string {
iterator := storeObj.Iterator(nil, nil)
defer iterator.Close()

keys := []string{}
for ; iterator.Valid(); iterator.Next() {
keys = append(keys, string(iterator.Key()))
}
return keys
}
70 changes: 61 additions & 9 deletions simulation/types/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,61 @@ func (sim *SimCtx) SelAddrWithDenoms(ctx sdk.Context, denoms []string) (simulati
return acc, sdk.Coins{}, false
}
balance := sim.RandCoinSubset(ctx, acc.Address, denoms)
return acc, balance, true
return acc, balance.Sort(), true
}

// SelAddrWithDenom attempts to find an address with the provided denom. This function
// returns (account, randSubsetCoins, found), so if found = false, then no such address exists.
// randSubsetCoins is a random subset of the provided denoms, if the account is found.
// TODO: Write unit test
func (sim *SimCtx) SelAddrWithDenom(ctx sdk.Context, denom string) (simulation.Account, sdk.Coin, bool) {
acc, subsetCoins, found := sim.SelAddrWithDenoms(ctx, []string{denom})
if !found {
return acc, sdk.Coin{}, found
}
return acc, subsetCoins[0], found
}

// GetRandSubsetOfKDenoms returns a random subset of coins of k unique denoms from the provided account
// TODO: Write unit test
func (sim *SimCtx) GetRandSubsetOfKDenoms(ctx sdk.Context, acc simulation.Account, k int) (sdk.Coins, bool) {
// get all spendable coins from provided account
coins := sim.BankKeeper().SpendableCoins(ctx, acc.Address)
// ensure account coins are greater than or equal to the requested subset length
if len(coins) < k {
return sdk.Coins{}, false
}
// randomly remove a denom from the coins array until we reach desired length
r := sim.GetSeededRand("select random seed")

for len(coins) != k {
index := r.Intn(len(coins) - 1)
coins = RemoveIndex(coins, index)
}
// append random amount less than or equal to existing amount to new subset array
subset := sdk.Coins{}
for _, c := range coins {
amt, err := simulation.RandPositiveInt(r, c.Amount)
if err != nil {
return sdk.Coins{}, false
}
subset = append(subset, sdk.NewCoin(c.Denom, amt))
}

// return nothing if the coin struct length is less than requested (sanity check)
if len(subset) < k {
return sdk.Coins{}, false
}

return subset.Sort(), true
}

// RandomSimAccountWithKDenoms returns an account that possesses k unique denoms
func (sim *SimCtx) RandomSimAccountWithKDenoms(ctx sdk.Context, k int) (simulation.Account, bool) {
accHasBal := func(acc simulation.Account) bool {
return len(sim.BankKeeper().SpendableCoins(ctx, acc.Address)) >= k
}
return sim.RandomSimAccountWithConstraint(accHasBal)
}

// RandGeometricCoin uniformly samples a denom from the addr's balances.
Expand Down Expand Up @@ -125,10 +179,7 @@ func (sim *SimCtx) RandCoinSubset(ctx sdk.Context, addr sdk.AccAddress, denoms [
subsetCoins := sdk.Coins{}
for _, denom := range denoms {
bal := sim.BankKeeper().GetBalance(ctx, addr, denom)
amt, err := sim.RandPositiveInt(bal.Amount)
if err != nil {
panic(err)
}
amt := sim.RandPositiveInt(bal.Amount)
subsetCoins = subsetCoins.Add(sdk.NewCoin(bal.Denom, amt))
}
return subsetCoins
Expand Down Expand Up @@ -157,14 +208,15 @@ func (sim *SimCtx) RandomFees(ctx sdk.Context, spendableCoins sdk.Coins) (sdk.Co
return nil, fmt.Errorf("no coins found for random fees")
}

amt, err := sim.RandPositiveInt(randCoin.Amount)
if err != nil {
return nil, err
}
amt := sim.RandPositiveInt(randCoin.Amount)

// Create a random fee and verify the fees are within the account's spendable
// balance.
fees := sdk.NewCoins(sdk.NewCoin(randCoin.Denom, amt))

return fees, nil
}

func RemoveIndex(s sdk.Coins, index int) sdk.Coins {
return append(s[:index], s[index+1:]...)
}
3 changes: 3 additions & 0 deletions simulation/types/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ func NewCurriedMsgBasedAction[K interface{}, M sdk.Msg](actionName string, k K,
return NewMsgBasedAction(actionName, msgGenerator)
}

// TODO: make API in simulator action collection interface
// to add a 'modulename' to many actions

type msgBasedAction struct {
name string
weight Weight
Expand Down
4 changes: 2 additions & 2 deletions simulation/types/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type AppModuleSimulationV2 interface {
type AppModuleSimulationV2WithRandGenesis interface {
AppModuleSimulationV2
// TODO: Come back and improve SimulationState interface
RandomGenesisState(*module.SimulationState, *SimCtx)
GenerateGenesisState(*module.SimulationState, *SimCtx)
}

// SimulationManager defines a simulation manager that provides the high level utility
Expand Down Expand Up @@ -141,7 +141,7 @@ func (m Manager) GenerateGenesisStates(simState *module.SimulationState, sim *Si
if simModule, ok := m.Modules[moduleName]; ok {
// if we define a random genesis function use it, otherwise use default genesis
if mod, ok := simModule.(AppModuleSimulationV2WithRandGenesis); ok {
mod.RandomGenesisState(simState, sim)
mod.GenerateGenesisState(simState, sim)
} else {
simState.GenState[simModule.Name()] = simModule.DefaultGenesis(simState.Cdc)
}
Expand Down
8 changes: 6 additions & 2 deletions simulation/types/randutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ func (sim *SimCtx) RandStringOfLength(n int) string {
}

// RandPositiveInt get a rand positive sdk.Int
func (sim *SimCtx) RandPositiveInt(max sdk.Int) (sdk.Int, error) {
func (sim *SimCtx) RandPositiveInt(max sdk.Int) sdk.Int {
r := sim.GetSeededRand("random bounded positive int")
return sdkrand.RandPositiveInt(r, max)
v, err := sdkrand.RandPositiveInt(r, max)
if err != nil {
panic(err)
}
return v
}

// RandomAmount generates a random amount
Expand Down
5 changes: 4 additions & 1 deletion simulation/types/txbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ func (sim *SimCtx) deliverTx(tx sdk.Tx, msg sdk.Msg, msgName string) (simulation
return simulation.NoOpMsg(msgName, msgName, fmt.Sprintf("unable to deliver tx. \nreason: %v\n results: %v\n msg: %s\n tx: %s", err, results, msg, tx)), nil, err
}

return simulation.NewOperationMsg(msg, true, "", nil), nil, nil
opMsg := simulation.NewOperationMsg(msg, true, "", nil)
opMsg.Route = msgName
opMsg.Name = msgName
return opMsg, nil, nil
}

// GenTx generates a signed mock transaction.
Expand Down
2 changes: 1 addition & 1 deletion tests/simulator/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestFullAppSimulation(t *testing.T) {
// -Enabled=true -NumBlocks=1000 -BlockSize=200 \
// -Period=1 -Commit=true -Seed=57 -v -timeout 24h
sdkSimapp.FlagEnabledValue = true
sdkSimapp.FlagNumBlocksValue = 100
sdkSimapp.FlagNumBlocksValue = 200
sdkSimapp.FlagBlockSizeValue = 25
sdkSimapp.FlagCommitValue = true
sdkSimapp.FlagVerboseValue = true
Expand Down
13 changes: 11 additions & 2 deletions x/gamm/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,19 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val
func (AppModule) ConsensusVersion() uint64 { return 1 }

// **** simulation implementation ****
// GenerateGenesisState creates a randomized GenState of the gamm module.
func (am AppModule) GenerateGenesisState(simState *module.SimulationState, s *simulation.SimCtx) {
DefaultGen := types.DefaultGenesis()
// change the pool creation fee denom from uosmo to stake
DefaultGen.Params.PoolCreationFee = sdk.NewCoins(gammsimulation.PoolCreationFee)
DefaultGenJson := simState.Cdc.MustMarshalJSON(DefaultGen)
simState.GenState[types.ModuleName] = DefaultGenJson
}

func (am AppModule) Actions() []simulation.Action {
return []simulation.Action{
simulation.NewMsgBasedAction("MsgJoinPool", gammsimulation.CurrySimMsgJoinPool(am.keeper)),
simulation.NewCurriedMsgBasedAction("Msg create univ2 pool", am.keeper, gammsimulation.RandomCreateUniv2PoolMsg),
simulation.NewCurriedMsgBasedAction("MsgJoinPool", am.keeper, gammsimulation.RandomJoinPoolMsg),
simulation.NewCurriedMsgBasedAction("MsgExitPool", am.keeper, gammsimulation.RandomExitPoolMsg),
simulation.NewCurriedMsgBasedAction("CreateUniV2Msg", am.keeper, gammsimulation.RandomCreateUniV2Msg),
}
}
Loading

0 comments on commit 17ebcc8

Please sign in to comment.