simulation: Allow operations to specify future operations
The intent of this is to allow for simulating things like slashing for not voting on a governance proposal. To test this, you would queue all the validator votes in future blocks, and keep track of which ones you didn't slash. Then you could add queue a "check governance slashing operation" after the voting period is over.
This commit is contained in:
@@ -70,6 +70,8 @@ func SimulateFromSeed(
|
||||
request := abci.RequestBeginBlock{Header: header}
|
||||
|
||||
var pastTimes []time.Time
|
||||
// These are operations which have been queued by previous operations
|
||||
operationQueue := make(map[int][]Operation)
|
||||
|
||||
for i := 0; i < numBlocks; i++ {
|
||||
|
||||
@@ -96,9 +98,14 @@ func SimulateFromSeed(
|
||||
default:
|
||||
thisBlockSize = r.Intn(blockSize * 4)
|
||||
}
|
||||
// Run queued operations. Ignores blocksize if blocksize is too small
|
||||
log, numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), t, r, app, ctx, keys, log, event)
|
||||
opCount += numQueuedOpsRan
|
||||
thisBlockSize -= numQueuedOpsRan
|
||||
for j := 0; j < thisBlockSize; j++ {
|
||||
logUpdate, err := ops[r.Intn(len(ops))](t, r, app, ctx, keys, log, event)
|
||||
logUpdate, futureOps, err := ops[r.Intn(len(ops))](t, r, app, ctx, keys, log, event)
|
||||
log += "\n" + logUpdate
|
||||
queueOperations(operationQueue, futureOps)
|
||||
|
||||
require.Nil(t, err, log)
|
||||
if onOperation {
|
||||
@@ -134,6 +141,39 @@ func SimulateFromSeed(
|
||||
DisplayEvents(events)
|
||||
}
|
||||
|
||||
// adds all future operations into the operation queue.
|
||||
func queueOperations(queuedOperations map[int][]Operation, futureOperations []FutureOperation) {
|
||||
if futureOperations == nil {
|
||||
return
|
||||
}
|
||||
for _, futureOp := range futureOperations {
|
||||
if val, ok := queuedOperations[futureOp.BlockHeight]; ok {
|
||||
queuedOperations[futureOp.BlockHeight] = append(val, futureOp.Op)
|
||||
} else {
|
||||
queuedOperations[futureOp.BlockHeight] = []Operation{futureOp.Op}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runQueuedOperations(queueOperations map[int][]Operation, height int, t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
privKeys []crypto.PrivKey, log string, event func(string)) (updatedLog string, numOpsRan int) {
|
||||
updatedLog = log
|
||||
if queuedOps, ok := queueOperations[height]; ok {
|
||||
numOps := len(queuedOps)
|
||||
for i := 0; i < numOps; 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.
|
||||
logUpdate, _, err := queuedOps[i](t, r, app, ctx, privKeys, updatedLog, event)
|
||||
updatedLog += "\n" + logUpdate
|
||||
require.Nil(t, err, updatedLog)
|
||||
}
|
||||
delete(queueOperations, height)
|
||||
return updatedLog, numOps
|
||||
}
|
||||
return log, 0
|
||||
}
|
||||
|
||||
func getKeys(validators map[string]mockValidator) []string {
|
||||
keys := make([]string, len(validators))
|
||||
i := 0
|
||||
|
||||
@@ -19,10 +19,13 @@ type (
|
||||
// For ease of debugging,
|
||||
// an operation returns a descriptive message "action",
|
||||
// which details what this fuzzed state machine transition actually did.
|
||||
//
|
||||
// Operations can optionally provide a list of "FutureOperations" to run later
|
||||
// These will be ran at the beginning of the corresponding block.
|
||||
Operation func(
|
||||
t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||
privKeys []crypto.PrivKey, log string, event func(string),
|
||||
) (action string, err sdk.Error)
|
||||
) (action string, futureOperations []FutureOperation, err sdk.Error)
|
||||
|
||||
// RandSetup performs the random setup the mock module needs.
|
||||
RandSetup func(r *rand.Rand, privKeys []crypto.PrivKey)
|
||||
@@ -36,6 +39,15 @@ type (
|
||||
val abci.Validator
|
||||
livenessState int
|
||||
}
|
||||
|
||||
// FutureOperation is an operation which will be ran at the
|
||||
// beginning of the provided 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
|
||||
Op Operation
|
||||
}
|
||||
)
|
||||
|
||||
// PeriodicInvariant returns an Invariant function closure that asserts
|
||||
|
||||
Reference in New Issue
Block a user