Skip to content

Commit

Permalink
Merge PR cosmos#3819: Simulation Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
rigelrozanski authored and cwgoes committed Mar 14, 2019
1 parent 48b6b38 commit f0d1efa
Show file tree
Hide file tree
Showing 22 changed files with 582 additions and 528 deletions.
7 changes: 7 additions & 0 deletions .pending/improvements/gaia/3819-Simulation-refa
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
\#3819 Simulation refactor, log output now stored in ~/.gaiad/simulation/
* Simulation moved to its own module (not a part of mock)
* Logger type instead of passing function variables everywhere
* Logger json output (for reloadable simulation running)
* Cleanup bank simulation messages / remove dup code in bank simulation
* Simulations saved in `~/.gaiad/simulations/`
* "Lean" simulation output option to exclude No-ops and !ok functions (`--SimulationLean` flag)
84 changes: 32 additions & 52 deletions cmd/gaia/app/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov"
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
"github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/cosmos/cosmos-sdk/x/slashing"
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
"github.com/cosmos/cosmos-sdk/x/staking"
Expand All @@ -43,19 +43,30 @@ var (
blockSize int
enabled bool
verbose bool
lean bool
commit bool
period int
)

func init() {
flag.StringVar(&genesisFile, "SimulationGenesis", "", "Custom simulation genesis file")
flag.Int64Var(&seed, "SimulationSeed", 42, "Simulation random seed")
flag.IntVar(&numBlocks, "SimulationNumBlocks", 500, "Number of blocks")
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "Operations per block")
flag.BoolVar(&enabled, "SimulationEnabled", false, "Enable the simulation")
flag.BoolVar(&verbose, "SimulationVerbose", false, "Verbose log output")
flag.BoolVar(&commit, "SimulationCommit", false, "Have the simulation commit")
flag.IntVar(&period, "SimulationPeriod", 1, "Run slow invariants only once every period assertions")
flag.StringVar(&genesisFile, "SimulationGenesis", "", "custom simulation genesis file")
flag.Int64Var(&seed, "SimulationSeed", 42, "simulation random seed")
flag.IntVar(&numBlocks, "SimulationNumBlocks", 500, "number of blocks")
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "operations per block")
flag.BoolVar(&enabled, "SimulationEnabled", false, "enable the simulation")
flag.BoolVar(&verbose, "SimulationVerbose", false, "verbose log output")
flag.BoolVar(&lean, "SimulationLean", false, "lean simulation log output")
flag.BoolVar(&commit, "SimulationCommit", false, "have the simulation commit")
flag.IntVar(&period, "SimulationPeriod", 1, "run slow invariants only once every period assertions")
}

// helper function for populating input for SimulateFromSeed
func getSimulateFromSeedInput(tb testing.TB, app *GaiaApp) (
testing.TB, *baseapp.BaseApp, simulation.AppStateFn, int64,
simulation.WeightedOperations, sdk.Invariants, int, int, bool, bool) {

return tb, app.BaseApp, appStateFn, seed,
testAndRunTxs(app), invariants(app), numBlocks, blockSize, commit, lean
}

func appStateFromGenesisFileFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
Expand Down Expand Up @@ -265,8 +276,8 @@ func randIntBetween(r *rand.Rand, min, max int) int {
func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
return []simulation.WeightedOperation{
{5, authsim.SimulateDeductFee(app.accountKeeper, app.feeCollectionKeeper)},
{100, banksim.SendMsg(app.accountKeeper, app.bankKeeper)},
{10, banksim.SingleInputMsgMultiSend(app.accountKeeper, app.bankKeeper)},
{100, banksim.SimulateMsgSend(app.accountKeeper, app.bankKeeper)},
{10, banksim.SimulateSingleInputMsgMultiSend(app.accountKeeper, app.bankKeeper)},
{50, distrsim.SimulateMsgSetWithdrawAddress(app.accountKeeper, app.distrKeeper)},
{50, distrsim.SimulateMsgWithdrawDelegatorReward(app.accountKeeper, app.distrKeeper)},
{50, distrsim.SimulateMsgWithdrawValidatorCommission(app.accountKeeper, app.distrKeeper)},
Expand Down Expand Up @@ -314,14 +325,7 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {

// Run randomized simulation
// TODO parameterize numbers, save for a later PR
_, err := simulation.SimulateFromSeed(
b, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
invariants(app), // these shouldn't get ran
numBlocks,
blockSize,
commit,
)
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(b, app))
if err != nil {
fmt.Println(err)
b.Fail()
Expand Down Expand Up @@ -356,14 +360,7 @@ func TestFullGaiaSimulation(t *testing.T) {
require.Equal(t, "GaiaApp", app.Name())

// Run randomized simulation
_, err := simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
invariants(app),
numBlocks,
blockSize,
commit,
)
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
Expand Down Expand Up @@ -397,14 +394,8 @@ func TestGaiaImportExport(t *testing.T) {
require.Equal(t, "GaiaApp", app.Name())

// Run randomized simulation
_, err := simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
invariants(app),
numBlocks,
blockSize,
commit,
)
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))

if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
Expand Down Expand Up @@ -446,7 +437,8 @@ func TestGaiaImportExport(t *testing.T) {
storeKeysPrefixes := []StoreKeysPrefixes{
{app.keyMain, newApp.keyMain, [][]byte{}},
{app.keyAccount, newApp.keyAccount, [][]byte{}},
{app.keyStaking, newApp.keyStaking, [][]byte{staking.UnbondingQueueKey, staking.RedelegationQueueKey, staking.ValidatorQueueKey}}, // ordering may change but it doesn't matter
{app.keyStaking, newApp.keyStaking, [][]byte{staking.UnbondingQueueKey,
staking.RedelegationQueueKey, staking.ValidatorQueueKey}}, // ordering may change but it doesn't matter
{app.keySlashing, newApp.keySlashing, [][]byte{}},
{app.keyMint, newApp.keyMint, [][]byte{}},
{app.keyDistr, newApp.keyDistr, [][]byte{}},
Expand Down Expand Up @@ -492,14 +484,8 @@ func TestGaiaSimulationAfterImport(t *testing.T) {
require.Equal(t, "GaiaApp", app.Name())

// Run randomized simulation
stopEarly, err := simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
invariants(app),
numBlocks,
blockSize,
commit,
)
stopEarly, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))

if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
Expand Down Expand Up @@ -537,14 +523,7 @@ func TestGaiaSimulationAfterImport(t *testing.T) {
})

// Run randomized simulation on imported app
_, err = simulation.SimulateFromSeed(
t, newApp.BaseApp, appStateFn, seed,
testAndRunTxs(newApp),
invariants(newApp),
numBlocks,
blockSize,
commit,
)
_, err = simulation.SimulateFromSeed(getSimulateFromSeedInput(t, newApp))
require.Nil(t, err)

}
Expand Down Expand Up @@ -575,6 +554,7 @@ func TestAppStateDeterminism(t *testing.T) {
50,
100,
true,
false,
)
appHash := app.LastCommitID().Hash
appHashList[j] = appHash
Expand Down
25 changes: 10 additions & 15 deletions x/auth/simulation/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,50 @@ package simulation

import (
"errors"
"fmt"
"math/big"
"math/rand"

"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
"github.com/cosmos/cosmos-sdk/x/simulation"
)

// SimulateDeductFee
func SimulateDeductFee(m auth.AccountKeeper, f auth.FeeCollectionKeeper) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
accs []simulation.Account, event func(string)) (
action string, fOp []simulation.FutureOperation, err error) {
accs []simulation.Account) (
opMsg simulation.OperationMsg, fOps []simulation.FutureOperation, err error) {

account := simulation.RandomAcc(r, accs)
stored := m.GetAccount(ctx, account.Address)
initCoins := stored.GetCoins()
opMsg = simulation.NewOperationMsgBasic("auth", "deduct_fee", "", false, nil)

if len(initCoins) == 0 {
event(fmt.Sprintf("auth/SimulateDeductFee/false"))
return action, nil, nil
return opMsg, nil, nil
}

denomIndex := r.Intn(len(initCoins))
randCoin := initCoins[denomIndex]

amt, err := randPositiveInt(r, randCoin.Amount)
if err != nil {
event(fmt.Sprintf("auth/SimulateDeductFee/false"))
return action, nil, nil
return opMsg, nil, nil
}

// Create a random fee and verify the fees are within the account's spendable
// balance.
fees := sdk.Coins{sdk.NewCoin(randCoin.Denom, amt)}
spendableCoins := stored.SpendableCoins(ctx.BlockHeader().Time)
if _, hasNeg := spendableCoins.SafeSub(fees); hasNeg {
event(fmt.Sprintf("auth/SimulateDeductFee/false"))
return action, nil, nil
return opMsg, nil, nil
}

// get the new account balance
newCoins, hasNeg := initCoins.SafeSub(fees)
if hasNeg {
event(fmt.Sprintf("auth/SimulateDeductFee/false"))
return action, nil, nil
return opMsg, nil, nil
}

if err := stored.SetCoins(newCoins); err != nil {
Expand All @@ -58,10 +54,9 @@ func SimulateDeductFee(m auth.AccountKeeper, f auth.FeeCollectionKeeper) simulat

m.SetAccount(ctx, stored)
f.AddCollectedFees(ctx, fees)
event(fmt.Sprintf("auth/SimulateDeductFee/true"))

action = "TestDeductFee"
return action, nil, nil
opMsg.OK = true
return opMsg, nil, nil
}
}

Expand Down
Loading

0 comments on commit f0d1efa

Please sign in to comment.