Remove code duplication

This commit is contained in:
ValarDragon 2018-08-30 00:13:31 -07:00
parent 31ca2e058b
commit 03d2f7331b
3 changed files with 61 additions and 88 deletions

View File

@ -123,10 +123,11 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {
// Run randomized simulation
// TODO parameterize numbers, save for a later PR
simulation.BenchmarkSimulationFromSeed(
simulation.SimulateFromSeed(
b, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
[]simulation.RandSetup{},
invariants(app), // these shouldn't get ran
10,
100,
false,

View File

@ -17,7 +17,6 @@ import (
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/mock"
"github.com/stretchr/testify/require"
)
// Simulate tests application by sending random messages.
@ -52,13 +51,22 @@ 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(
t *testing.T, 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 []Operation, setups []RandSetup,
invariants []Invariant, numBlocks int, blockSize int, commit bool,
) {
var t *testing.T
var b *testing.B
testingmode := false
if _t, ok := tb.(*testing.T); ok {
t = _t
testingmode = true
} else {
b = tb.(*testing.B)
}
log := fmt.Sprintf("Starting SimulateFromSeed with randomness created with seed %d", int(seed))
r := rand.New(rand.NewSource(seed))
timestamp := randTimestamp(r)
log = fmt.Sprintf("%s\nStarting the simulation from time %v, unixtime %v", log, timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
log = updateLog(testingmode, log, "Starting the simulation from time %v, unixtime %v", timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
fmt.Printf("%s\n", log)
timeDiff := maxTimePerBlock - minTimePerBlock
@ -67,7 +75,7 @@ func SimulateFromSeed(
// Setup event stats
events := make(map[string]uint)
event := func(what string) {
log += "\nevent - " + what
log = updateLog(testingmode, log, "event - "+what)
events[what]++
}
@ -82,32 +90,40 @@ func SimulateFromSeed(
// These are operations which have been queued by previous operations
operationQueue := make(map[int][]Operation)
if !testingmode {
b.ResetTimer()
}
for i := 0; i < numBlocks; i++ {
// Run the BeginBlock handler
app.BeginBlock(request)
log += "\nBeginBlock"
log = updateLog(testingmode, log, "BeginBlock")
// Make sure invariants hold at beginning of block
AssertAllInvariants(t, app, invariants, log)
if testingmode {
// Make sure invariants hold at beginning of block
AssertAllInvariants(t, app, invariants, log)
}
ctx := app.NewContext(false, header)
thisBlockSize := getBlockSize(r, blockSize)
// Run queued operations. Ignores blocksize if blocksize is too small
log, numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), t, r, app, ctx, keys, log, event)
log, numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, keys, log, event)
opCount += numQueuedOpsRan
thisBlockSize -= numQueuedOpsRan
for j := 0; j < thisBlockSize; j++ {
logUpdate, futureOps, err := ops[r.Intn(len(ops))](t, r, app, ctx, keys, log, event)
log += "\n" + logUpdate
require.Nil(t, err, log)
logUpdate, futureOps, err := ops[r.Intn(len(ops))](tb, r, app, ctx, keys, log, event)
log = updateLog(testingmode, log, logUpdate)
if err != nil {
tb.Fatalf("error on operation %d, %v", opCount, err)
}
queueOperations(operationQueue, futureOps)
if onOperation {
if onOperation && testingmode {
AssertAllInvariants(t, app, invariants, log)
}
if opCount%200 == 0 {
if testingmode && opCount%200 == 0 {
fmt.Printf("\rSimulating... block %d/%d, operation %d.", header.Height, numBlocks, opCount)
}
opCount++
@ -119,8 +135,10 @@ func SimulateFromSeed(
header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
log += "\nEndBlock"
// Make sure invariants hold at end of block
AssertAllInvariants(t, app, invariants, log)
if testingmode {
// Make sure invariants hold at end of block
AssertAllInvariants(t, app, invariants, log)
}
if commit {
app.Commit()
}
@ -129,13 +147,23 @@ func SimulateFromSeed(
request = RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, lastHeaderTime, event, header, log)
// Update the validator set
validators = updateValidators(t, r, validators, res.ValidatorUpdates, event)
validators = updateValidators(tb, r, validators, res.ValidatorUpdates, event)
}
fmt.Printf("\nSimulation complete. Final height (blocks): %d, final time (seconds): %v\n", header.Height, header.Time)
if testingmode {
fmt.Printf("\nSimulation complete. Final height (blocks): %d, final time (seconds): %v\n", header.Height, header.Time)
}
DisplayEvents(events)
}
func updateLog(testingmode bool, log string, update string, args ...interface{}) (updatedLog string) {
if testingmode == true {
update = fmt.Sprintf(update, args)
return fmt.Sprintf("%s\n%s", log, update)
}
return ""
}
func getBlockSize(r *rand.Rand, blockSize int) int {
load := r.Float64()
switch {
@ -148,69 +176,6 @@ func getBlockSize(r *rand.Rand, blockSize int) int {
}
}
// Simulate from seed, benchmarks
func BenchmarkSimulationFromSeed(b *testing.B, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage,
seed int64, ops []Operation, setups []RandSetup, numBlocks int, blockSize int, commit bool) {
r := rand.New(rand.NewSource(seed))
timestamp := randTimestamp(r)
timeDiff := maxTimePerBlock - minTimePerBlock
keys, accs := mock.GeneratePrivKeyAddressPairsFromRand(r, numKeys)
// Setup event stats
events := make(map[string]uint)
event := func(what string) {
events[what]++
}
validators := initChain(r, keys, accs, setups, app, appStateFn)
header := abci.Header{Height: 0, Time: timestamp}
opCount := 0
request := abci.RequestBeginBlock{Header: header}
var lastHeaderTime time.Time
// These are operations which have been queued by previous operations
operationQueue := make(map[int][]Operation)
b.ResetTimer()
for i := 0; i < numBlocks; i++ {
// Run the BeginBlock handler
app.BeginBlock(request)
ctx := app.NewContext(false, header)
thisBlockSize := getBlockSize(r, blockSize)
// Run queued operations. Ignores blocksize if blocksize is too small
log, numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), b, r, app, ctx, keys, "", event)
opCount += numQueuedOpsRan
thisBlockSize -= numQueuedOpsRan
for j := 0; j < thisBlockSize; j++ {
_, futureOps, err := ops[r.Intn(len(ops))](b, r, app, ctx, keys, "", event)
queueOperations(operationQueue, futureOps)
if err != nil {
b.Fatalf("error on operation %d, %v", opCount, err)
}
opCount++
}
res := app.EndBlock(abci.RequestEndBlock{})
header.Height++
lastHeaderTime = header.Time
header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
if commit {
app.Commit()
}
// Generate a random RequestBeginBlock with the current validator set for the next block
request = RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, lastHeaderTime, event, header, log)
// Update the validator set
validators = updateValidators(b, r, validators, res.ValidatorUpdates, event)
}
DisplayEvents(events)
fmt.Printf("Benchmark simulation ran %d operations\n", opCount)
}
// adds all future operations into the operation queue.
func queueOperations(queuedOperations map[int][]Operation, futureOperations []FutureOperation) {
if futureOperations == nil {

View File

@ -17,6 +17,7 @@ import (
// SimulateMsgCreateValidator
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
denom := k.GetParams(ctx).BondDenom
description := stake.Description{
@ -43,7 +44,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
}
ctx, write := ctx.CacheContext()
result := stake.NewHandler(k)(ctx, msg)
result := handler(ctx, msg)
if result.IsOK() {
write()
}
@ -56,6 +57,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
// SimulateMsgEditValidator
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
description := stake.Description{
Moniker: simulation.RandStringOfLength(r, 10),
@ -74,7 +76,7 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
}
ctx, write := ctx.CacheContext()
result := stake.NewHandler(k)(ctx, msg)
result := handler(ctx, msg)
if result.IsOK() {
write()
}
@ -86,6 +88,7 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
// SimulateMsgDelegate
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
denom := k.GetParams(ctx).BondDenom
validatorKey := simulation.RandomKey(r, keys)
@ -108,7 +111,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
}
ctx, write := ctx.CacheContext()
result := stake.NewHandler(k)(ctx, msg)
result := handler(ctx, msg)
if result.IsOK() {
write()
}
@ -120,6 +123,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
// SimulateMsgBeginUnbonding
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
denom := k.GetParams(ctx).BondDenom
validatorKey := simulation.RandomKey(r, keys)
@ -142,7 +146,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
}
ctx, write := ctx.CacheContext()
result := stake.NewHandler(k)(ctx, msg)
result := handler(ctx, msg)
if result.IsOK() {
write()
}
@ -154,6 +158,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
// SimulateMsgCompleteUnbonding
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
validatorKey := simulation.RandomKey(r, keys)
validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address())
@ -167,7 +172,7 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
}
ctx, write := ctx.CacheContext()
result := stake.NewHandler(k)(ctx, msg)
result := handler(ctx, msg)
if result.IsOK() {
write()
}
@ -179,6 +184,7 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
// SimulateMsgBeginRedelegate
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
denom := k.GetParams(ctx).BondDenom
sourceValidatorKey := simulation.RandomKey(r, keys)
@ -205,7 +211,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
}
ctx, write := ctx.CacheContext()
result := stake.NewHandler(k)(ctx, msg)
result := handler(ctx, msg)
if result.IsOK() {
write()
}
@ -217,6 +223,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
// SimulateMsgCompleteRedelegate
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
handler := stake.NewHandler(k)
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
validatorSrcKey := simulation.RandomKey(r, keys)
validatorSrcAddress := sdk.AccAddress(validatorSrcKey.PubKey().Address())
@ -233,7 +240,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
}
ctx, write := ctx.CacheContext()
result := stake.NewHandler(k)(ctx, msg)
result := handler(ctx, msg)
if result.IsOK() {
write()
}