From e4b5e2c9f3e23376b33d38c8db93e74292dc2281 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Sun, 28 Oct 2018 21:37:19 -0700 Subject: [PATCH] Make simulation use a transition matrix for block size This enables simulating periods of high load, and periods of low to no load. (low load because future ops will still terminate in that time frame) --- PENDING.md | 1 + client/lcd/certificates.go | 2 +- x/mock/simulation/constants.go | 6 +++ x/mock/simulation/random_simulate_blocks.go | 41 ++++++++++++--------- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/PENDING.md b/PENDING.md index aa7cca2c4..a43485beb 100644 --- a/PENDING.md +++ b/PENDING.md @@ -37,6 +37,7 @@ IMPROVEMENTS * SDK - #2573 [x/distribution] add accum invariance + - \#1924 [simulation] Use a transition matrix for block size * Tendermint diff --git a/client/lcd/certificates.go b/client/lcd/certificates.go index 1516ed35a..f47f2397c 100644 --- a/client/lcd/certificates.go +++ b/client/lcd/certificates.go @@ -43,7 +43,7 @@ func generateSelfSignedCert(host string) (certBytes []byte, priv *ecdsa.PrivateK KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, - IsCA: true, + IsCA: true, } hosts := strings.Split(host, ",") for _, h := range hosts { diff --git a/x/mock/simulation/constants.go b/x/mock/simulation/constants.go index a96d4541f..2c4543b72 100644 --- a/x/mock/simulation/constants.go +++ b/x/mock/simulation/constants.go @@ -28,4 +28,10 @@ var ( {10, 50, 5}, {0, 10, 1000}, }) + // 3 states: rand in range [0, 4*provided blocksize], rand in range [0, 2 * provided blocksize], 0 + blockSizeTransitionMatrix, _ = CreateTransitionMatrix([][]int{ + {85, 5, 0}, + {15, 92, 1}, + {0, 3, 99}, + }) ) diff --git a/x/mock/simulation/random_simulate_blocks.go b/x/mock/simulation/random_simulate_blocks.go index 2506af377..78939698b 100644 --- a/x/mock/simulation/random_simulate_blocks.go +++ b/x/mock/simulation/random_simulate_blocks.go @@ -108,7 +108,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, blockLogBuilders = make([]*strings.Builder, numBlocks) } displayLogs := logPrinter(testingMode, blockLogBuilders) - blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, timeOperationQueue, numBlocks, displayLogs) + blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, timeOperationQueue, numBlocks, blockSize, displayLogs) if !testingMode { b.ResetTimer() } else { @@ -142,7 +142,6 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, } ctx := app.NewContext(false, header) - thisBlockSize := getBlockSize(r, blockSize) // Run queued operations. Ignores blocksize if blocksize is too small logWriter("Queued operations") @@ -153,9 +152,8 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp, assertAllInvariants(t, app, header, invariants, "QueuedOperations", displayLogs) } - thisBlockSize = thisBlockSize - numQueuedOpsRan - numQueuedTimeOpsRan logWriter("Standard operations") - operations := blockSimulator(thisBlockSize, r, app, ctx, accs, header, logWriter) + operations := blockSimulator(r, app, ctx, accs, header, logWriter) opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan if testingMode { // Make sure invariants hold at end of block @@ -200,9 +198,14 @@ 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 []FutureOperation, totalNumBlocks int, displayLogs func()) func( - blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) { - totalOpWeight := 0 +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, avgBlockSize int, displayLogs func()) func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) { + var ( + lastBlocksizeState = 0 // state for [4 * uniform distribution] + totalOpWeight = 0 + blocksize int + ) + for i := 0; i < len(ops); i++ { totalOpWeight += ops[i].Weight } @@ -217,8 +220,10 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event f // shouldn't happen return ops[0].Op } - return func(blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + + return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []Account, header abci.Header, logWriter func(string)) (opCount int) { + lastBlocksizeState, blocksize = getBlockSize(r, lastBlocksizeState, avgBlockSize) for j := 0; j < blocksize; j++ { logUpdate, futureOps, err := selectOp(r)(r, app, ctx, accounts, event) if err != nil { @@ -253,16 +258,18 @@ func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B return } -func getBlockSize(r *rand.Rand, blockSize int) int { - load := r.Float64() - switch { - case load < 0.33: - return 0 - case load < 0.66: - return r.Intn(blockSize * 2) - default: - return r.Intn(blockSize * 4) +func getBlockSize(r *rand.Rand, lastBlockSizeState, avgBlockSize int) (state, blocksize int) { + // TODO: Make blockSizeTransitionMatrix non-global + // TODO: Make default blocksize transitition matrix actually make the average blocksize equal to avgBlockSize + state = blockSizeTransitionMatrix.NextState(r, lastBlockSizeState) + if state == 0 { + blocksize = r.Intn(avgBlockSize * 4) + } else if state == 1 { + blocksize = r.Intn(avgBlockSize * 2) + } else { + blocksize = 0 } + return } // adds all future operations into the operation queue.