Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: Simulation Queued Time Operations #2348

Merged
merged 4 commits into from
Sep 19, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion x/gov/simulation/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ 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
Expand Down
47 changes: 39 additions & 8 deletions x/mock/simulation/random_simulate_blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 := []FutureOperation{}
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 {
Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you combine the lines subtracting the block size?

operations := blockSimulator(thisBlockSize, r, app, ctx, keys, header, logWriter)
opCount += operations + numQueuedOpsRan
opCount += operations + numQueuedOpsRan + numQueuedTimeOpsRan

res := app.EndBlock(abci.RequestEndBlock{})
header.Height++
Expand Down Expand Up @@ -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 []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++ {
Expand All @@ -200,7 +203,7 @@ func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event f
}
logWriter(logUpdate)

queueOperations(operationQueue, futureOps)
queueOperations(operationQueue, timeOperationQueue, futureOps)
if testingMode {
if onOperation {
assertAllInvariants(t, app, invariants, displayLogs)
Expand Down Expand Up @@ -239,15 +242,22 @@ func getBlockSize(r *rand.Rand, blockSize int) int {
}

// adds all future operations into the operation queue.
func queueOperations(queuedOperations map[int][]Operation, futureOperations []FutureOperation) {
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) })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we have to do a search, can you make a TODO comment to make the queued time ops a sorted data structure? (This can then be addressed #postlaunch or if it bottlenecks the simulation)

Right now we have to copy all the time ops on insertion / deletion, which is an O(N) operation.

queuedTimeOperations = append(queuedTimeOperations, FutureOperation{})
copy(queuedTimeOperations[index+1:], queuedTimeOperations[index:])
queuedTimeOperations[index] = futureOp
}
}
}
Expand All @@ -274,6 +284,27 @@ func runQueuedOperations(queueOperations map[int][]Operation, height int, tb tes
return 0
}

// nolint: errcheck
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do want this passing errcheck though. Is there a specific line/error your trying to skip?

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
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
Expand Down
3 changes: 3 additions & 0 deletions x/mock/simulation/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package simulation

import (
"math/rand"
"time"

"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -41,10 +42,12 @@ 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
}

Expand Down