From 654cc2d6ebd9992036088341fbb5b0a6b9933fcb Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Mon, 17 Sep 2018 18:22:47 -0700 Subject: [PATCH 1/4] queue time operations simulation --- x/bank/simulation/msgs.go | 10 ++--- x/gov/simulation/msgs.go | 30 ++++++------- x/mock/simulation/random_simulate_blocks.go | 50 ++++++++++++++++++--- x/mock/simulation/types.go | 10 ++++- x/slashing/simulation/msgs.go | 6 +-- x/stake/simulation/msgs.go | 50 ++++++++++----------- 6 files changed, 101 insertions(+), 55 deletions(-) diff --git a/x/bank/simulation/msgs.go b/x/bank/simulation/msgs.go index cefa2a460b75..0a7219658b74 100644 --- a/x/bank/simulation/msgs.go +++ b/x/bank/simulation/msgs.go @@ -18,7 +18,7 @@ import ( // SimulateSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both // accounts already exist. func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation { - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, fTOps []simulation.FutureTimeOperation, err error) { fromKey := simulation.RandomKey(r, keys) fromAddr := sdk.AccAddress(fromKey.PubKey().Address()) toKey := simulation.RandomKey(r, keys) @@ -33,13 +33,13 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation initFromCoins := mapper.GetAccount(ctx, fromAddr).GetCoins() if len(initFromCoins) == 0 { - return "skipping, no coins at all", nil, nil + return "skipping, no coins at all", nil, nil, nil } denomIndex := r.Intn(len(initFromCoins)) amt, goErr := randPositiveInt(r, initFromCoins[denomIndex].Amount) if goErr != nil { - return "skipping bank send due to account having no coins of denomination " + initFromCoins[denomIndex].Denom, nil, nil + return "skipping bank send due to account having no coins of denomination " + initFromCoins[denomIndex].Denom, nil, nil, nil } action = fmt.Sprintf("%s is sending %s %s to %s", @@ -56,11 +56,11 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation } goErr = sendAndVerifyMsgSend(app, mapper, msg, ctx, []crypto.PrivKey{fromKey}) if goErr != nil { - return "", nil, goErr + return "", nil, nil, goErr } event("bank/sendAndVerifyMsgSend/ok") - return action, nil, nil + return action, nil, nil, nil } } diff --git a/x/gov/simulation/msgs.go b/x/gov/simulation/msgs.go index 4ca1cdf44509..d84cb253e746 100644 --- a/x/gov/simulation/msgs.go +++ b/x/gov/simulation/msgs.go @@ -44,17 +44,17 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe }) statePercentageArray := []float64{1, .9, .75, .4, .15, 0} curNumVotesState := 1 - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, fTOps []simulation.FutureTimeOperation, err error) { // 1) submit proposal now sender := simulation.RandomKey(r, keys) msg, err := simulationCreateMsgSubmitProposal(r, sender) if err != nil { - return "", nil, err + return "", nil, nil, err } action, ok := simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event) // don't schedule votes if proposal failed if !ok { - return action, nil, nil + return action, nil, nil, nil } proposalID := k.GetLastProposalID(ctx) // 2) Schedule operations for votes @@ -75,7 +75,7 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe // TODO: Find a way to check if a validator was slashed other than just checking their balance a block // before and after. - return action, fops, nil + return action, fops, nil, nil } } @@ -83,14 +83,14 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe // Note: Currently doesn't ensure that the proposal txt is in JSON form func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation { handler := gov.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, fTOps []simulation.FutureTimeOperation, err error) { sender := simulation.RandomKey(r, keys) msg, err := simulationCreateMsgSubmitProposal(r, sender) if err != nil { - return "", nil, err + return "", nil, nil, err } action, _ = simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event) - return action, nil, nil + return action, nil, nil, nil } } @@ -128,17 +128,17 @@ func simulationCreateMsgSubmitProposal(r *rand.Rand, sender crypto.PrivKey) (msg // SimulateMsgDeposit func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation { - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { key := simulation.RandomKey(r, keys) addr := sdk.AccAddress(key.PubKey().Address()) proposalID, ok := randomProposalID(r, k, ctx) if !ok { - return "no-operation", nil, nil + return "no-operation", nil, nil, nil } deposit := randomDeposit(r) msg := gov.NewMsgDeposit(addr, proposalID, deposit) if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := gov.NewHandler(k)(ctx, msg) @@ -151,7 +151,7 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation { } event(fmt.Sprintf("gov/MsgDeposit/%v", result.IsOK())) action = fmt.Sprintf("TestMsgDeposit: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil + return action, nil, nil, nil } } @@ -163,7 +163,7 @@ func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation { // nolint: unparam func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, proposalID int64) simulation.Operation { - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { if key == nil { key = simulation.RandomKey(r, keys) } @@ -173,7 +173,7 @@ func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, if proposalID < 0 { proposalID, ok = randomProposalID(r, k, ctx) if !ok { - return "no-operation", nil, nil + return "no-operation", nil, nil, nil } } addr := sdk.AccAddress(key.PubKey().Address()) @@ -181,7 +181,7 @@ func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, msg := gov.NewMsgVote(addr, proposalID, option) if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() @@ -192,7 +192,7 @@ func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, event(fmt.Sprintf("gov/MsgVote/%v", result.IsOK())) action = fmt.Sprintf("TestMsgVote: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil + return action, nil, nil, nil } } diff --git a/x/mock/simulation/random_simulate_blocks.go b/x/mock/simulation/random_simulate_blocks.go index de78ae0942fb..7b10158f9128 100644 --- a/x/mock/simulation/random_simulate_blocks.go +++ b/x/mock/simulation/random_simulate_blocks.go @@ -98,13 +98,14 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, request := RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header) // These are operations which have been queued by previous operations operationQueue := make(map[int][]Operation) + timeOperationQueue := []FutureTimeOperation{} var blockLogBuilders []*strings.Builder if testingMode { blockLogBuilders = make([]*strings.Builder, numBlocks) } displayLogs := logPrinter(testingMode, blockLogBuilders) - blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, numBlocks, displayLogs) + blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, timeOperationQueue, numBlocks, displayLogs) if !testingMode { b.ResetTimer() } else { @@ -140,8 +141,10 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, // Run queued operations. Ignores blocksize if blocksize is too small numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, keys, logWriter, displayLogs, event) thisBlockSize -= numQueuedOpsRan + numQueuedTimeOpsRan := runQueuedTimeOperations(timeOperationQueue, header.Time, tb, r, app, ctx, keys, logWriter, displayLogs, event) + thisBlockSize -= numQueuedTimeOpsRan operations := blockSimulator(thisBlockSize, r, app, ctx, keys, header, logWriter) - opCount += operations + numQueuedOpsRan + opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan res := app.EndBlock(abci.RequestEndBlock{}) header.Height++ @@ -173,7 +176,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, // 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 []WeightedOperation, 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, timeOperationQueue []FutureTimeOperation, 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++ { @@ -193,7 +196,7 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event f 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 := selectOp(r)(r, app, ctx, keys, event) + logUpdate, futureOps, futureTimeOps, 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) @@ -201,6 +204,7 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event f logWriter(logUpdate) queueOperations(operationQueue, futureOps) + queueTimeOperations(timeOperationQueue, futureTimeOps) if testingMode { if onOperation { assertAllInvariants(t, app, invariants, displayLogs) @@ -238,7 +242,7 @@ func getBlockSize(r *rand.Rand, blockSize int) int { } } -// adds all future operations into the operation queue. +// adds all future Height based operations into the operation queue. func queueOperations(queuedOperations map[int][]Operation, futureOperations []FutureOperation) { if futureOperations == nil { return @@ -261,7 +265,7 @@ func runQueuedOperations(queueOperations map[int][]Operation, height int, tb tes // For now, queued operations cannot queue more operations. // If a need arises for us to support queued messages to queue more messages, this can // be changed. - logUpdate, _, err := queuedOps[i](r, app, ctx, privKeys, event) + logUpdate, _, _, err := queuedOps[i](r, app, ctx, privKeys, event) logWriter(logUpdate) if err != nil { displayLogs() @@ -274,6 +278,40 @@ func runQueuedOperations(queueOperations map[int][]Operation, height int, tb tes return 0 } +// adds all future Time-based operations into the operation queue. +func queueTimeOperations(queuedTimeOperations []FutureTimeOperation, futureTimeOperations []FutureTimeOperation) { + if queuedTimeOperations == nil { + return + } + for _, futureOp := range futureTimeOperations { + index := sort.Search(len(queuedTimeOperations), func(i int) bool { return queuedTimeOperations[i].BlockTime.After(futureOp.BlockTime) }) + queuedTimeOperations = append(queuedTimeOperations, FutureTimeOperation{}) + copy(queuedTimeOperations[index+1:], queuedTimeOperations[index:]) + queuedTimeOperations[index] = futureOp + } +} + +// nolint: errcheck +func runQueuedTimeOperations(queueOperations []FutureTimeOperation, currentTime time.Time, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + privKeys []crypto.PrivKey, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) { + + numOpsRan = 0 + for len(queueOperations) > 0 && currentTime.After(queueOperations[0].BlockTime) { + // For now, queued operations cannot queue more operations. + // If a need arises for us to support queued messages to queue more messages, this can + // be changed. + logUpdate, _, _, err := queueOperations[0].Op(r, app, ctx, privKeys, event) + logWriter(logUpdate) + if err != nil { + displayLogs() + tb.FailNow() + } + queueOperations = queueOperations[1:] + numOpsRan++ + } + return numOpsRan +} + func getKeys(validators map[string]mockValidator) []string { keys := make([]string, len(validators)) i := 0 diff --git a/x/mock/simulation/types.go b/x/mock/simulation/types.go index 401899efe3f4..f2a76079a69d 100644 --- a/x/mock/simulation/types.go +++ b/x/mock/simulation/types.go @@ -2,6 +2,7 @@ package simulation import ( "math/rand" + "time" "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" @@ -23,7 +24,7 @@ type ( // These will be ran at the beginning of the corresponding block. Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, privKeys []crypto.PrivKey, event func(string), - ) (action string, futureOperations []FutureOperation, err error) + ) (action string, futureOperations []FutureOperation, FutureTimeOperations []FutureTimeOperation, err error) // RandSetup performs the random setup the mock module needs. RandSetup func(r *rand.Rand, privKeys []crypto.PrivKey) @@ -48,6 +49,13 @@ type ( Op Operation } + // FutureTimeOperation is an operation which will be ran at the + // first block after the provided BlockTime. + FutureTimeOperation struct { + BlockTime time.Time + Op Operation + } + // WeightedOperation is an operation with associated weight. // This is used to bias the selection operation within the simulator. WeightedOperation struct { diff --git a/x/slashing/simulation/msgs.go b/x/slashing/simulation/msgs.go index da9340baf46d..fd40f7053185 100644 --- a/x/slashing/simulation/msgs.go +++ b/x/slashing/simulation/msgs.go @@ -14,12 +14,12 @@ import ( // SimulateMsgUnjail func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation { - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { key := simulation.RandomKey(r, keys) address := sdk.ValAddress(key.PubKey().Address()) msg := slashing.NewMsgUnjail(address) if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := slashing.NewHandler(k)(ctx, msg) @@ -28,6 +28,6 @@ func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation { } event(fmt.Sprintf("slashing/MsgUnjail/%v", result.IsOK())) action = fmt.Sprintf("TestMsgUnjail: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil + return action, nil, nil, nil } } diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index 5b2bc1ee8151..19dcab652cb1 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -17,7 +17,7 @@ import ( // SimulateMsgCreateValidator func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { denom := k.GetParams(ctx).BondDenom description := stake.Description{ @@ -31,7 +31,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation amount = simulation.RandomAmount(r, amount) } if amount.Equal(sdk.ZeroInt()) { - return "no-operation", nil, nil + return "no-operation", nil, nil, nil } msg := stake.MsgCreateValidator{ Description: description, @@ -41,7 +41,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation Delegation: sdk.NewCoin(denom, amount), } if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -51,14 +51,14 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation event(fmt.Sprintf("stake/MsgCreateValidator/%v", result.IsOK())) // require.True(t, result.IsOK(), "expected OK result but instead got %v", result) action = fmt.Sprintf("TestMsgCreateValidator: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil + return action, nil, nil, nil } } // SimulateMsgEditValidator func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { description := stake.Description{ Moniker: simulation.RandStringOfLength(r, 10), @@ -74,7 +74,7 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation { ValidatorAddr: address, } if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -83,14 +83,14 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation { } event(fmt.Sprintf("stake/MsgEditValidator/%v", result.IsOK())) action = fmt.Sprintf("TestMsgEditValidator: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil + return action, nil, nil, nil } } // SimulateMsgDelegate func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { denom := k.GetParams(ctx).BondDenom validatorKey := simulation.RandomKey(r, keys) @@ -102,7 +102,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat amount = simulation.RandomAmount(r, amount) } if amount.Equal(sdk.ZeroInt()) { - return "no-operation", nil, nil + return "no-operation", nil, nil, nil } msg := stake.MsgDelegate{ DelegatorAddr: delegatorAddress, @@ -110,7 +110,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat Delegation: sdk.NewCoin(denom, amount), } if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -119,14 +119,14 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat } event(fmt.Sprintf("stake/MsgDelegate/%v", result.IsOK())) action = fmt.Sprintf("TestMsgDelegate: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil + return action, nil, nil, nil } } // SimulateMsgBeginUnbonding func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { denom := k.GetParams(ctx).BondDenom validatorKey := simulation.RandomKey(r, keys) @@ -138,7 +138,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. amount = simulation.RandomAmount(r, amount) } if amount.Equal(sdk.ZeroInt()) { - return "no-operation", nil, nil + return "no-operation", nil, nil, nil } msg := stake.MsgBeginUnbonding{ DelegatorAddr: delegatorAddress, @@ -146,7 +146,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. SharesAmount: sdk.NewDecFromInt(amount), } if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -155,14 +155,14 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. } event(fmt.Sprintf("stake/MsgBeginUnbonding/%v", result.IsOK())) action = fmt.Sprintf("TestMsgBeginUnbonding: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil + return action, nil, nil, nil } } // SimulateMsgCompleteUnbonding func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { validatorKey := simulation.RandomKey(r, keys) validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address()) @@ -173,7 +173,7 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation { ValidatorAddr: validatorAddress, } if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -182,14 +182,14 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation { } event(fmt.Sprintf("stake/MsgCompleteUnbonding/%v", result.IsOK())) action = fmt.Sprintf("TestMsgCompleteUnbonding: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil + return action, nil, nil, nil } } // SimulateMsgBeginRedelegate func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { denom := k.GetParams(ctx).BondDenom sourceValidatorKey := simulation.RandomKey(r, keys) @@ -204,7 +204,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation amount = simulation.RandomAmount(r, amount) } if amount.Equal(sdk.ZeroInt()) { - return "no-operation", nil, nil + return "no-operation", nil, nil, nil } msg := stake.MsgBeginRedelegate{ DelegatorAddr: delegatorAddress, @@ -213,7 +213,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation SharesAmount: sdk.NewDecFromInt(amount), } if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -222,14 +222,14 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation } event(fmt.Sprintf("stake/MsgBeginRedelegate/%v", result.IsOK())) action = fmt.Sprintf("TestMsgBeginRedelegate: %s", msg.GetSignBytes()) - return action, nil, nil + return action, nil, nil, nil } } // SimulateMsgCompleteRedelegate func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { validatorSrcKey := simulation.RandomKey(r, keys) validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address()) @@ -243,7 +243,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation { ValidatorDstAddr: validatorDstAddress, } if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -252,7 +252,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation { } event(fmt.Sprintf("stake/MsgCompleteRedelegate/%v", result.IsOK())) action = fmt.Sprintf("TestMsgCompleteRedelegate: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil + return action, nil, nil, nil } } From 058e470301d9fe188658307a0ba7c36e4a450481 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Mon, 17 Sep 2018 20:23:50 -0700 Subject: [PATCH 2/4] removed FutureTimeOperation --- x/bank/simulation/msgs.go | 10 ++--- x/gov/simulation/msgs.go | 32 ++++++------- x/mock/simulation/random_simulate_blocks.go | 45 ++++++++----------- x/mock/simulation/types.go | 11 ++--- x/slashing/simulation/msgs.go | 6 +-- x/stake/simulation/msgs.go | 50 ++++++++++----------- 6 files changed, 71 insertions(+), 83 deletions(-) diff --git a/x/bank/simulation/msgs.go b/x/bank/simulation/msgs.go index 0a7219658b74..cefa2a460b75 100644 --- a/x/bank/simulation/msgs.go +++ b/x/bank/simulation/msgs.go @@ -18,7 +18,7 @@ import ( // SimulateSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both // accounts already exist. func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation { - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, fTOps []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, err error) { fromKey := simulation.RandomKey(r, keys) fromAddr := sdk.AccAddress(fromKey.PubKey().Address()) toKey := simulation.RandomKey(r, keys) @@ -33,13 +33,13 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation initFromCoins := mapper.GetAccount(ctx, fromAddr).GetCoins() if len(initFromCoins) == 0 { - return "skipping, no coins at all", nil, nil, nil + return "skipping, no coins at all", nil, nil } denomIndex := r.Intn(len(initFromCoins)) amt, goErr := randPositiveInt(r, initFromCoins[denomIndex].Amount) if goErr != nil { - return "skipping bank send due to account having no coins of denomination " + initFromCoins[denomIndex].Denom, nil, nil, nil + return "skipping bank send due to account having no coins of denomination " + initFromCoins[denomIndex].Denom, nil, nil } action = fmt.Sprintf("%s is sending %s %s to %s", @@ -56,11 +56,11 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation } goErr = sendAndVerifyMsgSend(app, mapper, msg, ctx, []crypto.PrivKey{fromKey}) if goErr != nil { - return "", nil, nil, goErr + return "", nil, goErr } event("bank/sendAndVerifyMsgSend/ok") - return action, nil, nil, nil + return action, nil, nil } } diff --git a/x/gov/simulation/msgs.go b/x/gov/simulation/msgs.go index d84cb253e746..168081b188c9 100644 --- a/x/gov/simulation/msgs.go +++ b/x/gov/simulation/msgs.go @@ -44,17 +44,17 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe }) statePercentageArray := []float64{1, .9, .75, .4, .15, 0} curNumVotesState := 1 - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, fTOps []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, err error) { // 1) submit proposal now sender := simulation.RandomKey(r, keys) msg, err := simulationCreateMsgSubmitProposal(r, sender) if err != nil { - return "", nil, nil, err + return "", nil, err } action, ok := simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event) // don't schedule votes if proposal failed if !ok { - return action, nil, nil, nil + return action, nil, nil } proposalID := k.GetLastProposalID(ctx) // 2) Schedule operations for votes @@ -69,13 +69,13 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe fops := make([]simulation.FutureOperation, numVotes+1) for i := 0; i < numVotes; i++ { whenVote := ctx.BlockHeight() + r.Int63n(votingPeriod) - fops[i] = simulation.FutureOperation{int(whenVote), operationSimulateMsgVote(k, sk, keys[whoVotes[i]], proposalID)} + fops[i] = simulation.FutureOperation{BlockHeight: int(whenVote), Op: operationSimulateMsgVote(k, sk, keys[whoVotes[i]], proposalID)} } // 3) Make an operation to ensure slashes were done correctly. (Really should be a future invariant) // TODO: Find a way to check if a validator was slashed other than just checking their balance a block // before and after. - return action, fops, nil, nil + return action, fops, nil } } @@ -83,14 +83,14 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe // Note: Currently doesn't ensure that the proposal txt is in JSON form func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation { handler := gov.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, fTOps []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOps []simulation.FutureOperation, err error) { sender := simulation.RandomKey(r, keys) msg, err := simulationCreateMsgSubmitProposal(r, sender) if err != nil { - return "", nil, nil, err + return "", nil, err } action, _ = simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event) - return action, nil, nil, nil + return action, nil, nil } } @@ -128,17 +128,17 @@ func simulationCreateMsgSubmitProposal(r *rand.Rand, sender crypto.PrivKey) (msg // SimulateMsgDeposit func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation { - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { key := simulation.RandomKey(r, keys) addr := sdk.AccAddress(key.PubKey().Address()) proposalID, ok := randomProposalID(r, k, ctx) if !ok { - return "no-operation", nil, nil, nil + return "no-operation", nil, nil } deposit := randomDeposit(r) msg := gov.NewMsgDeposit(addr, proposalID, deposit) if msg.ValidateBasic() != nil { - return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := gov.NewHandler(k)(ctx, msg) @@ -151,7 +151,7 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation { } event(fmt.Sprintf("gov/MsgDeposit/%v", result.IsOK())) action = fmt.Sprintf("TestMsgDeposit: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil, nil + return action, nil, nil } } @@ -163,7 +163,7 @@ func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation { // nolint: unparam func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, proposalID int64) simulation.Operation { - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { if key == nil { key = simulation.RandomKey(r, keys) } @@ -173,7 +173,7 @@ func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, if proposalID < 0 { proposalID, ok = randomProposalID(r, k, ctx) if !ok { - return "no-operation", nil, nil, nil + return "no-operation", nil, nil } } addr := sdk.AccAddress(key.PubKey().Address()) @@ -181,7 +181,7 @@ func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, msg := gov.NewMsgVote(addr, proposalID, option) if msg.ValidateBasic() != nil { - return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() @@ -192,7 +192,7 @@ func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, event(fmt.Sprintf("gov/MsgVote/%v", result.IsOK())) action = fmt.Sprintf("TestMsgVote: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil, nil + return action, nil, nil } } diff --git a/x/mock/simulation/random_simulate_blocks.go b/x/mock/simulation/random_simulate_blocks.go index 7b10158f9128..846178cf9595 100644 --- a/x/mock/simulation/random_simulate_blocks.go +++ b/x/mock/simulation/random_simulate_blocks.go @@ -98,7 +98,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, request := RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header) // These are operations which have been queued by previous operations operationQueue := make(map[int][]Operation) - timeOperationQueue := []FutureTimeOperation{} + timeOperationQueue := []FutureOperation{} var blockLogBuilders []*strings.Builder if testingMode { @@ -176,7 +176,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, // 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 []WeightedOperation, operationQueue map[int][]Operation, timeOperationQueue []FutureTimeOperation, 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, timeOperationQueue []FutureOperation, 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++ { @@ -196,15 +196,14 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event f 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, futureTimeOps, err := selectOp(r)(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) } logWriter(logUpdate) - queueOperations(operationQueue, futureOps) - queueTimeOperations(timeOperationQueue, futureTimeOps) + queueOperations(operationQueue, timeOperationQueue, futureOps) if testingMode { if onOperation { assertAllInvariants(t, app, invariants, displayLogs) @@ -242,16 +241,23 @@ func getBlockSize(r *rand.Rand, blockSize int) int { } } -// adds all future Height based operations into the operation queue. -func queueOperations(queuedOperations map[int][]Operation, futureOperations []FutureOperation) { +// adds all future operations into the operation queue. +func queueOperations(queuedOperations map[int][]Operation, queuedTimeOperations []FutureOperation, futureOperations []FutureOperation) { if futureOperations == nil { return } for _, futureOp := range futureOperations { - if val, ok := queuedOperations[futureOp.BlockHeight]; ok { - queuedOperations[futureOp.BlockHeight] = append(val, futureOp.Op) + if futureOp.BlockHeight != 0 { + if val, ok := queuedOperations[futureOp.BlockHeight]; ok { + queuedOperations[futureOp.BlockHeight] = append(val, futureOp.Op) + } else { + queuedOperations[futureOp.BlockHeight] = []Operation{futureOp.Op} + } } else { - queuedOperations[futureOp.BlockHeight] = []Operation{futureOp.Op} + index := sort.Search(len(queuedTimeOperations), func(i int) bool { return queuedTimeOperations[i].BlockTime.After(futureOp.BlockTime) }) + queuedTimeOperations = append(queuedTimeOperations, FutureOperation{}) + copy(queuedTimeOperations[index+1:], queuedTimeOperations[index:]) + queuedTimeOperations[index] = futureOp } } } @@ -265,7 +271,7 @@ func runQueuedOperations(queueOperations map[int][]Operation, height int, tb tes // For now, queued operations cannot queue more operations. // If a need arises for us to support queued messages to queue more messages, this can // be changed. - logUpdate, _, _, err := queuedOps[i](r, app, ctx, privKeys, event) + logUpdate, _, err := queuedOps[i](r, app, ctx, privKeys, event) logWriter(logUpdate) if err != nil { displayLogs() @@ -278,21 +284,8 @@ func runQueuedOperations(queueOperations map[int][]Operation, height int, tb tes return 0 } -// adds all future Time-based operations into the operation queue. -func queueTimeOperations(queuedTimeOperations []FutureTimeOperation, futureTimeOperations []FutureTimeOperation) { - if queuedTimeOperations == nil { - return - } - for _, futureOp := range futureTimeOperations { - index := sort.Search(len(queuedTimeOperations), func(i int) bool { return queuedTimeOperations[i].BlockTime.After(futureOp.BlockTime) }) - queuedTimeOperations = append(queuedTimeOperations, FutureTimeOperation{}) - copy(queuedTimeOperations[index+1:], queuedTimeOperations[index:]) - queuedTimeOperations[index] = futureOp - } -} - // nolint: errcheck -func runQueuedTimeOperations(queueOperations []FutureTimeOperation, currentTime time.Time, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, +func runQueuedTimeOperations(queueOperations []FutureOperation, currentTime time.Time, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, privKeys []crypto.PrivKey, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) { numOpsRan = 0 @@ -300,7 +293,7 @@ func runQueuedTimeOperations(queueOperations []FutureTimeOperation, currentTime // For now, queued operations cannot queue more operations. // If a need arises for us to support queued messages to queue more messages, this can // be changed. - logUpdate, _, _, err := queueOperations[0].Op(r, app, ctx, privKeys, event) + logUpdate, _, err := queueOperations[0].Op(r, app, ctx, privKeys, event) logWriter(logUpdate) if err != nil { displayLogs() diff --git a/x/mock/simulation/types.go b/x/mock/simulation/types.go index f2a76079a69d..a32edea6d6c4 100644 --- a/x/mock/simulation/types.go +++ b/x/mock/simulation/types.go @@ -24,7 +24,7 @@ type ( // These will be ran at the beginning of the corresponding block. Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, privKeys []crypto.PrivKey, event func(string), - ) (action string, futureOperations []FutureOperation, FutureTimeOperations []FutureTimeOperation, err error) + ) (action string, futureOperations []FutureOperation, err error) // RandSetup performs the random setup the mock module needs. RandSetup func(r *rand.Rand, privKeys []crypto.PrivKey) @@ -42,20 +42,15 @@ type ( // FutureOperation is an operation which will be ran at the // beginning of the provided BlockHeight. + // If both a BlockHeight and BlockTime are specified, it will use the BlockHeight. // In the (likely) event that multiple operations are queued at the same // block height, they will execute in a FIFO pattern. FutureOperation struct { BlockHeight int + BlockTime time.Time Op Operation } - // FutureTimeOperation is an operation which will be ran at the - // first block after the provided BlockTime. - FutureTimeOperation struct { - BlockTime time.Time - Op Operation - } - // WeightedOperation is an operation with associated weight. // This is used to bias the selection operation within the simulator. WeightedOperation struct { diff --git a/x/slashing/simulation/msgs.go b/x/slashing/simulation/msgs.go index fd40f7053185..da9340baf46d 100644 --- a/x/slashing/simulation/msgs.go +++ b/x/slashing/simulation/msgs.go @@ -14,12 +14,12 @@ import ( // SimulateMsgUnjail func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation { - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { key := simulation.RandomKey(r, keys) address := sdk.ValAddress(key.PubKey().Address()) msg := slashing.NewMsgUnjail(address) if msg.ValidateBasic() != nil { - return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := slashing.NewHandler(k)(ctx, msg) @@ -28,6 +28,6 @@ func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation { } event(fmt.Sprintf("slashing/MsgUnjail/%v", result.IsOK())) action = fmt.Sprintf("TestMsgUnjail: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil, nil + return action, nil, nil } } diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index 19dcab652cb1..5b2bc1ee8151 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -17,7 +17,7 @@ import ( // SimulateMsgCreateValidator func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { denom := k.GetParams(ctx).BondDenom description := stake.Description{ @@ -31,7 +31,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation amount = simulation.RandomAmount(r, amount) } if amount.Equal(sdk.ZeroInt()) { - return "no-operation", nil, nil, nil + return "no-operation", nil, nil } msg := stake.MsgCreateValidator{ Description: description, @@ -41,7 +41,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation Delegation: sdk.NewCoin(denom, amount), } if msg.ValidateBasic() != nil { - return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -51,14 +51,14 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation event(fmt.Sprintf("stake/MsgCreateValidator/%v", result.IsOK())) // require.True(t, result.IsOK(), "expected OK result but instead got %v", result) action = fmt.Sprintf("TestMsgCreateValidator: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil, nil + return action, nil, nil } } // SimulateMsgEditValidator func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { description := stake.Description{ Moniker: simulation.RandStringOfLength(r, 10), @@ -74,7 +74,7 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation { ValidatorAddr: address, } if msg.ValidateBasic() != nil { - return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -83,14 +83,14 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation { } event(fmt.Sprintf("stake/MsgEditValidator/%v", result.IsOK())) action = fmt.Sprintf("TestMsgEditValidator: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil, nil + return action, nil, nil } } // SimulateMsgDelegate func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { denom := k.GetParams(ctx).BondDenom validatorKey := simulation.RandomKey(r, keys) @@ -102,7 +102,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat amount = simulation.RandomAmount(r, amount) } if amount.Equal(sdk.ZeroInt()) { - return "no-operation", nil, nil, nil + return "no-operation", nil, nil } msg := stake.MsgDelegate{ DelegatorAddr: delegatorAddress, @@ -110,7 +110,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat Delegation: sdk.NewCoin(denom, amount), } if msg.ValidateBasic() != nil { - return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -119,14 +119,14 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat } event(fmt.Sprintf("stake/MsgDelegate/%v", result.IsOK())) action = fmt.Sprintf("TestMsgDelegate: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil, nil + return action, nil, nil } } // SimulateMsgBeginUnbonding func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { denom := k.GetParams(ctx).BondDenom validatorKey := simulation.RandomKey(r, keys) @@ -138,7 +138,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. amount = simulation.RandomAmount(r, amount) } if amount.Equal(sdk.ZeroInt()) { - return "no-operation", nil, nil, nil + return "no-operation", nil, nil } msg := stake.MsgBeginUnbonding{ DelegatorAddr: delegatorAddress, @@ -146,7 +146,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. SharesAmount: sdk.NewDecFromInt(amount), } if msg.ValidateBasic() != nil { - return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -155,14 +155,14 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. } event(fmt.Sprintf("stake/MsgBeginUnbonding/%v", result.IsOK())) action = fmt.Sprintf("TestMsgBeginUnbonding: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil, nil + return action, nil, nil } } // SimulateMsgCompleteUnbonding func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { validatorKey := simulation.RandomKey(r, keys) validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address()) @@ -173,7 +173,7 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation { ValidatorAddr: validatorAddress, } if msg.ValidateBasic() != nil { - return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -182,14 +182,14 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation { } event(fmt.Sprintf("stake/MsgCompleteUnbonding/%v", result.IsOK())) action = fmt.Sprintf("TestMsgCompleteUnbonding: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil, nil + return action, nil, nil } } // SimulateMsgBeginRedelegate func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { denom := k.GetParams(ctx).BondDenom sourceValidatorKey := simulation.RandomKey(r, keys) @@ -204,7 +204,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation amount = simulation.RandomAmount(r, amount) } if amount.Equal(sdk.ZeroInt()) { - return "no-operation", nil, nil, nil + return "no-operation", nil, nil } msg := stake.MsgBeginRedelegate{ DelegatorAddr: delegatorAddress, @@ -213,7 +213,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation SharesAmount: sdk.NewDecFromInt(amount), } if msg.ValidateBasic() != nil { - return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -222,14 +222,14 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation } event(fmt.Sprintf("stake/MsgBeginRedelegate/%v", result.IsOK())) action = fmt.Sprintf("TestMsgBeginRedelegate: %s", msg.GetSignBytes()) - return action, nil, nil, nil + return action, nil, nil } } // SimulateMsgCompleteRedelegate func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation { handler := stake.NewHandler(k) - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, fTOp []simulation.FutureTimeOperation, err error) { + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { validatorSrcKey := simulation.RandomKey(r, keys) validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address()) @@ -243,7 +243,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation { ValidatorDstAddr: validatorDstAddress, } if msg.ValidateBasic() != nil { - return "", nil, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -252,7 +252,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation { } event(fmt.Sprintf("stake/MsgCompleteRedelegate/%v", result.IsOK())) action = fmt.Sprintf("TestMsgCompleteRedelegate: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) - return action, nil, nil, nil + return action, nil, nil } } From a8dbc967bf9e4e5ecf832413382e758e146efaee Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 18 Sep 2018 07:18:06 -0700 Subject: [PATCH 3/4] address dev's review --- x/mock/simulation/random_simulate_blocks.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x/mock/simulation/random_simulate_blocks.go b/x/mock/simulation/random_simulate_blocks.go index 846178cf9595..96dbff57253f 100644 --- a/x/mock/simulation/random_simulate_blocks.go +++ b/x/mock/simulation/random_simulate_blocks.go @@ -140,9 +140,8 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, // Run queued operations. Ignores blocksize if blocksize is too small numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, keys, logWriter, displayLogs, event) - thisBlockSize -= numQueuedOpsRan numQueuedTimeOpsRan := runQueuedTimeOperations(timeOperationQueue, header.Time, tb, r, app, ctx, keys, logWriter, displayLogs, event) - thisBlockSize -= numQueuedTimeOpsRan + thisBlockSize = thisBlockSize - numQueuedOpsRan - numQueuedTimeOpsRan operations := blockSimulator(thisBlockSize, r, app, ctx, keys, header, logWriter) opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan @@ -254,6 +253,7 @@ func queueOperations(queuedOperations map[int][]Operation, queuedTimeOperations queuedOperations[futureOp.BlockHeight] = []Operation{futureOp.Op} } } else { + // TODO: Replace with proper sorted data structure, so don't have the copy entire slice index := sort.Search(len(queuedTimeOperations), func(i int) bool { return queuedTimeOperations[i].BlockTime.After(futureOp.BlockTime) }) queuedTimeOperations = append(queuedTimeOperations, FutureOperation{}) copy(queuedTimeOperations[index+1:], queuedTimeOperations[index:]) @@ -284,7 +284,6 @@ func runQueuedOperations(queueOperations map[int][]Operation, height int, tb tes return 0 } -// nolint: errcheck func runQueuedTimeOperations(queueOperations []FutureOperation, currentTime time.Time, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, privKeys []crypto.PrivKey, logWriter func(string), displayLogs func(), event func(string)) (numOpsRan int) { From 7d4a75f5824fbb3e571612bb70daec50424cde25 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 18 Sep 2018 15:20:50 -0700 Subject: [PATCH 4/4] PENDING --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index 13443441188b..75d0fe62acae 100644 --- a/PENDING.md +++ b/PENDING.md @@ -80,6 +80,7 @@ FEATURES * [querier] added custom querier functionality, so ABCI query requests can be handled by keepers * [simulation] [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) allow operations to specify future operations * [simulation] [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) Add benchmarking capabilities, with makefile commands "test_sim_gaia_benchmark, test_sim_gaia_profile" + * [simulation] [\#2349](https://github.com/cosmos/cosmos-sdk/issues/2349) Add time-based future scheduled operations to simulator * Tendermint