From 92425c4e02646b552b99024b6a7ad65b3e3cbae9 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Mon, 10 Sep 2018 15:52:09 -0700 Subject: [PATCH] simulation: Add weighted operation --- Makefile | 2 +- PENDING.md | 1 + cmd/gaia/app/sim_test.go | 26 ++++++++++----------- x/bank/simulation/sim_test.go | 4 ++-- x/gov/simulation/sim_test.go | 14 +++++------ x/mock/simulation/random_simulate_blocks.go | 23 ++++++++++++++---- x/mock/simulation/types.go | 7 ++++++ x/stake/simulation/sim_test.go | 16 ++++++------- 8 files changed, 58 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 88ead03e6a99..ee76c6d197ce 100644 --- a/Makefile +++ b/Makefile @@ -157,7 +157,7 @@ test_sim_gaia_nondeterminism: test_sim_gaia_fast: @echo "Running quick Gaia simulation. This may take several minutes..." - @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=200 -v -timeout 24h + @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=400 -SimulationBlockSize=200 -v -timeout 24h test_sim_gaia_slow: @echo "Running full Gaia simulation. This may take awhile!" diff --git a/PENDING.md b/PENDING.md index 331d1fc85200..d959c1f434ad 100644 --- a/PENDING.md +++ b/PENDING.md @@ -106,6 +106,7 @@ IMPROVEMENTS * [store] \#1952, \#2281 Update IAVL dependency to v0.11.0 * [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153) * [simulation] Make logs not just pure strings, speeding it up by a large factor at greater block heights \#2282 + * [simulation] Add a concept of weighting the operations \#2303 * Tendermint diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index e809495fc69f..717b71e7263a 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -89,19 +89,19 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json return appState } -func testAndRunTxs(app *GaiaApp) []simulation.Operation { - return []simulation.Operation{ - banksim.SimulateSingleInputMsgSend(app.accountMapper), - govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, app.stakeKeeper), - govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper), - stakesim.SimulateMsgCreateValidator(app.accountMapper, app.stakeKeeper), - stakesim.SimulateMsgEditValidator(app.stakeKeeper), - stakesim.SimulateMsgDelegate(app.accountMapper, app.stakeKeeper), - stakesim.SimulateMsgBeginUnbonding(app.accountMapper, app.stakeKeeper), - stakesim.SimulateMsgCompleteUnbonding(app.stakeKeeper), - stakesim.SimulateMsgBeginRedelegate(app.accountMapper, app.stakeKeeper), - stakesim.SimulateMsgCompleteRedelegate(app.stakeKeeper), - slashingsim.SimulateMsgUnjail(app.slashingKeeper), +func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation { + return []simulation.WeightedOperation{ + {100, banksim.SimulateSingleInputMsgSend(app.accountMapper)}, + {5, govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, app.stakeKeeper)}, + {100, govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper)}, + {100, stakesim.SimulateMsgCreateValidator(app.accountMapper, app.stakeKeeper)}, + {5, stakesim.SimulateMsgEditValidator(app.stakeKeeper)}, + {100, stakesim.SimulateMsgDelegate(app.accountMapper, app.stakeKeeper)}, + {100, stakesim.SimulateMsgBeginUnbonding(app.accountMapper, app.stakeKeeper)}, + {100, stakesim.SimulateMsgCompleteUnbonding(app.stakeKeeper)}, + {100, stakesim.SimulateMsgBeginRedelegate(app.accountMapper, app.stakeKeeper)}, + {100, stakesim.SimulateMsgCompleteRedelegate(app.stakeKeeper)}, + {100, slashingsim.SimulateMsgUnjail(app.slashingKeeper)}, } } diff --git a/x/bank/simulation/sim_test.go b/x/bank/simulation/sim_test.go index 38461bad4709..4ecb30f34549 100644 --- a/x/bank/simulation/sim_test.go +++ b/x/bank/simulation/sim_test.go @@ -33,8 +33,8 @@ func TestBankWithRandomMessages(t *testing.T) { simulation.Simulate( t, mapp.BaseApp, appStateFn, - []simulation.Operation{ - SimulateSingleInputMsgSend(mapper), + []simulation.WeightedOperation{ + {1, SimulateSingleInputMsgSend(mapper)}, }, []simulation.RandSetup{}, []simulation.Invariant{ diff --git a/x/gov/simulation/sim_test.go b/x/gov/simulation/sim_test.go index 317864a61263..6c3f8bbb939a 100644 --- a/x/gov/simulation/sim_test.go +++ b/x/gov/simulation/sim_test.go @@ -56,10 +56,10 @@ func TestGovWithRandomMessages(t *testing.T) { // Test with unscheduled votes simulation.Simulate( t, mapp.BaseApp, appStateFn, - []simulation.Operation{ - SimulateMsgSubmitProposal(govKeeper, stakeKeeper), - SimulateMsgDeposit(govKeeper, stakeKeeper), - SimulateMsgVote(govKeeper, stakeKeeper), + []simulation.WeightedOperation{ + {2, SimulateMsgSubmitProposal(govKeeper, stakeKeeper)}, + {3, SimulateMsgDeposit(govKeeper, stakeKeeper)}, + {20, SimulateMsgVote(govKeeper, stakeKeeper)}, }, []simulation.RandSetup{ setup, }, []simulation.Invariant{ @@ -71,9 +71,9 @@ func TestGovWithRandomMessages(t *testing.T) { // Test with scheduled votes simulation.Simulate( t, mapp.BaseApp, appStateFn, - []simulation.Operation{ - SimulateSubmittingVotingAndSlashingForProposal(govKeeper, stakeKeeper), - SimulateMsgDeposit(govKeeper, stakeKeeper), + []simulation.WeightedOperation{ + {10, SimulateSubmittingVotingAndSlashingForProposal(govKeeper, stakeKeeper)}, + {5, SimulateMsgDeposit(govKeeper, stakeKeeper)}, }, []simulation.RandSetup{ setup, }, []simulation.Invariant{ diff --git a/x/mock/simulation/random_simulate_blocks.go b/x/mock/simulation/random_simulate_blocks.go index 08b70d1018db..4e6eeb267cf8 100644 --- a/x/mock/simulation/random_simulate_blocks.go +++ b/x/mock/simulation/random_simulate_blocks.go @@ -24,7 +24,7 @@ import ( // Simulate tests application by sending random messages. func Simulate( - t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, ops []Operation, setups []RandSetup, + t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, ops []WeightedOperation, setups []RandSetup, invariants []Invariant, numBlocks int, blockSize int, commit bool, ) { time := time.Now().UnixNano() @@ -54,7 +54,7 @@ func randTimestamp(r *rand.Rand) time.Time { // SimulateFromSeed tests an application by running the provided // operations, testing the provided invariants, but using the provided seed. func SimulateFromSeed( - tb testing.TB, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, seed int64, ops []Operation, setups []RandSetup, + tb testing.TB, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, seed int64, ops []WeightedOperation, setups []RandSetup, invariants []Invariant, numBlocks int, blockSize int, commit bool, ) { testingMode, t, b := getTestingMode(tb) @@ -153,12 +153,27 @@ func SimulateFromSeed( // Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize // memory overhead -func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event func(string), invariants []Invariant, ops []Operation, operationQueue map[int][]Operation, totalNumBlocks int, displayLogs func()) func( +func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event func(string), invariants []Invariant, ops []WeightedOperation, operationQueue map[int][]Operation, totalNumBlocks int, displayLogs func()) func( blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, privKeys []crypto.PrivKey, header abci.Header, logWriter func(string)) (opCount int) { + totalOpWeight := 0 + for i := 0; i < len(ops); i++ { + totalOpWeight += ops[i].Weight + } + selectOp := func(r *rand.Rand) Operation { + x := r.Intn(totalOpWeight) + for i := 0; i < len(ops); i++ { + if x <= ops[i].Weight { + return ops[i].Op + } + x -= ops[i].Weight + } + // shouldn't happen + return ops[0].Op + } return func(blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, header abci.Header, logWriter func(string)) (opCount int) { for j := 0; j < blocksize; j++ { - logUpdate, futureOps, err := ops[r.Intn(len(ops))](r, app, ctx, keys, event) + logUpdate, futureOps, err := selectOp(r)(r, app, ctx, keys, event) if err != nil { displayLogs() tb.Fatalf("error on operation %d within block %d, %v", header.Height, opCount, err) diff --git a/x/mock/simulation/types.go b/x/mock/simulation/types.go index 25fb1a6e8a53..401899efe3f4 100644 --- a/x/mock/simulation/types.go +++ b/x/mock/simulation/types.go @@ -47,6 +47,13 @@ type ( BlockHeight int Op Operation } + + // WeightedOperation is an operation with associated weight. + // This is used to bias the selection operation within the simulator. + WeightedOperation struct { + Weight int + Op Operation + } ) // PeriodicInvariant returns an Invariant function closure that asserts diff --git a/x/stake/simulation/sim_test.go b/x/stake/simulation/sim_test.go index 3feec637ba30..4dc4d4232cc0 100644 --- a/x/stake/simulation/sim_test.go +++ b/x/stake/simulation/sim_test.go @@ -44,14 +44,14 @@ func TestStakeWithRandomMessages(t *testing.T) { simulation.Simulate( t, mapp.BaseApp, appStateFn, - []simulation.Operation{ - SimulateMsgCreateValidator(mapper, stakeKeeper), - SimulateMsgEditValidator(stakeKeeper), - SimulateMsgDelegate(mapper, stakeKeeper), - SimulateMsgBeginUnbonding(mapper, stakeKeeper), - SimulateMsgCompleteUnbonding(stakeKeeper), - SimulateMsgBeginRedelegate(mapper, stakeKeeper), - SimulateMsgCompleteRedelegate(stakeKeeper), + []simulation.WeightedOperation{ + {10, SimulateMsgCreateValidator(mapper, stakeKeeper)}, + {5, SimulateMsgEditValidator(stakeKeeper)}, + {15, SimulateMsgDelegate(mapper, stakeKeeper)}, + {10, SimulateMsgBeginUnbonding(mapper, stakeKeeper)}, + {3, SimulateMsgCompleteUnbonding(stakeKeeper)}, + {10, SimulateMsgBeginRedelegate(mapper, stakeKeeper)}, + {3, SimulateMsgCompleteRedelegate(stakeKeeper)}, }, []simulation.RandSetup{ Setup(mapp, stakeKeeper), }, []simulation.Invariant{