diff --git a/x/mock/simulation/invariants.go b/x/mock/simulation/invariants.go index b8f9aad21d..23686005d1 100644 --- a/x/mock/simulation/invariants.go +++ b/x/mock/simulation/invariants.go @@ -13,16 +13,16 @@ import ( // The simulator will then halt and print the logs. type Invariant func(app *baseapp.BaseApp) error -// assertAllInvariants asserts a list of provided invariants against -// application state -func assertAllInvariants(t *testing.T, app *baseapp.BaseApp, - invariants []Invariant, where string, displayLogs func()) { +// group of Invarient +type Invariants []Invariant - for i := 0; i < len(invariants); i++ { - err := invariants[i](app) - if err != nil { - fmt.Printf("Invariants broken after %s\n", where) - fmt.Println(err.Error()) +// assertAll asserts the all invariants against application state +func (invs Invariants) assertAll(t *testing.T, app *baseapp.BaseApp, + event string, displayLogs func()) { + + for i := 0; i < len(invs); i++ { + if err := invs[i](app); err != nil { + fmt.Printf("Invariants broken after %s\n%s\n", event, err.Error()) displayLogs() t.Fatal() } diff --git a/x/mock/simulation/operation.go b/x/mock/simulation/operation.go index 21b606b373..27757df2d5 100644 --- a/x/mock/simulation/operation.go +++ b/x/mock/simulation/operation.go @@ -2,6 +2,7 @@ package simulation import ( "math/rand" + "sort" "time" "github.com/cosmos/cosmos-sdk/baseapp" @@ -24,6 +25,41 @@ type Operation func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, // queue of operations type OperationQueue map[int][]Operation +// adds all future operations into the operation queue. +func queueOperations(queuedOps OperationQueue, + queuedTimeOps []FutureOperation, + futureOps []FutureOperation) { + + if futureOps == nil { + return + } + + for _, futureOp := range futureOps { + if futureOp.BlockHeight != 0 { + if val, ok := queuedOps[futureOp.BlockHeight]; ok { + queuedOps[futureOp.BlockHeight] = append(val, futureOp.Op) + } else { + queuedOps[futureOp.BlockHeight] = []Operation{futureOp.Op} + } + continue + } + + // TODO: Replace with proper sorted data structure, so don't have the + // copy entire slice + index := sort.Search( + len(queuedTimeOps), + func(i int) bool { + return queuedTimeOps[i].BlockTime.After(futureOp.BlockTime) + }, + ) + queuedTimeOps = append(queuedTimeOps, FutureOperation{}) + copy(queuedTimeOps[index+1:], queuedTimeOps[index:]) + queuedTimeOps[index] = futureOp + } +} + +//________________________________________________________________________ + // 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 @@ -34,6 +70,8 @@ type FutureOperation struct { Op Operation } +//________________________________________________________________________ + // WeightedOperation is an operation with associated weight. // This is used to bias the selection operation within the simulator. type WeightedOperation struct { diff --git a/x/mock/simulation/simulate.go b/x/mock/simulation/simulate.go index 849f4eeaef..d9b5176f8c 100644 --- a/x/mock/simulation/simulate.go +++ b/x/mock/simulation/simulate.go @@ -7,7 +7,6 @@ import ( "os" "os/signal" "runtime/debug" - "sort" "strings" "syscall" "testing" @@ -27,7 +26,7 @@ type RandSetup func(r *rand.Rand, accounts []Account) func Simulate(t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, accs []Account) json.RawMessage, ops []WeightedOperation, setups []RandSetup, - invariants []Invariant, numBlocks int, blockSize int, commit bool) error { + invariants Invariants, numBlocks int, blockSize int, commit bool) error { time := time.Now().UnixNano() return SimulateFromSeed(t, app, appStateFn, time, ops, @@ -55,7 +54,7 @@ func initChain(r *rand.Rand, params Params, // operations, testing the provided invariants, but using the provided seed. func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, accs []Account) json.RawMessage, - seed int64, ops []WeightedOperation, setups []RandSetup, invariants []Invariant, + seed int64, ops WeightedOperations, setups []RandSetup, invariants Invariants, numBlocks int, blockSize int, commit bool) (simError error) { // in case we have to end early, don't os.Exit so that we can run cleanup code. @@ -154,7 +153,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, if testingMode { // Make sure invariants hold at beginning of block - assertAllInvariants(t, app, invariants, "BeginBlock", displayLogs) + invariants.assertAll(t, app, "BeginBlock", displayLogs) } ctx := app.NewContext(false, header) @@ -171,15 +170,15 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, logWriter, displayLogs, event) if testingMode && onOperation { // Make sure invariants hold at end of queued operations - assertAllInvariants(t, app, invariants, "QueuedOperations", displayLogs) + invariants.assertAll(t, app, "QueuedOperations", displayLogs) } logWriter("Standard operations") operations := blockSimulator(r, app, ctx, accs, header, logWriter) opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan if testingMode { - // Make sure invariants hold at end of block - assertAllInvariants(t, app, invariants, "StandardOperations", displayLogs) + // Make sure invariants hold at the operation + invariants.assertAll(t, app, "StandardOperations", displayLogs) } res := app.EndBlock(abci.RequestEndBlock{}) @@ -193,7 +192,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, if testingMode { // Make sure invariants hold at end of block - assertAllInvariants(t, app, invariants, "EndBlock", displayLogs) + invariants.assertAll(t, app, "EndBlock", displayLogs) } if commit { app.Commit() @@ -235,7 +234,7 @@ type blockSimFn func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, // 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, params Params, - event func(string), invariants []Invariant, ops WeightedOperations, + event func(string), invariants Invariants, ops WeightedOperations, operationQueue map[int][]Operation, timeOperationQueue []FutureOperation, totalNumBlocks int, avgBlockSize int, displayLogs func()) blockSimFn { @@ -262,8 +261,8 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params queueOperations(operationQueue, timeOperationQueue, futureOps) if testingMode { if onOperation { - assertAllInvariants(t, app, invariants, - fmt.Sprintf("operation: %v", logUpdate), displayLogs) + eventStr := fmt.Sprintf("operation: %v", logUpdate) + invariants.assertAll(t, app, eventStr, displayLogs) } if opCount%50 == 0 { fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", @@ -276,37 +275,6 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, params } } -// 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 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 { - // 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:]) - queuedTimeOperations[index] = futureOp - } - } -} - // nolint: errcheck func runQueuedOperations(queueOps map[int][]Operation, height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, @@ -318,8 +286,8 @@ func runQueuedOperations(queueOps map[int][]Operation, return 0 } - numOps := len(queuedOp) - for i := 0; i < numOps; i++ { + numOpsRan = len(queuedOp) + for i := 0; i < numOpsRan; i++ { // 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. @@ -331,7 +299,7 @@ func runQueuedOperations(queueOps map[int][]Operation, } } delete(queueOps, height) - return numOps + return numOpsRan } func runQueuedTimeOperations(queueOps []FutureOperation,