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:
ValarDragon 2018-08-27 14:27:00 -07:00
parent df70a34c45
commit 855222e8c3
9 changed files with 94 additions and 42 deletions

View File

@ -41,6 +41,7 @@ FEATURES
* SDK * SDK
* [querier] added custom querier functionality, so ABCI query requests can be handled by keepers * [querier] added custom querier functionality, so ABCI query requests can be handled by keepers
* [simulation] \#1924 allow operations to specify future operations
* Tendermint * Tendermint

View File

@ -3,7 +3,6 @@ package app
import ( import (
"encoding/json" "encoding/json"
"flag" "flag"
"fmt"
"math/rand" "math/rand"
"testing" "testing"
@ -87,7 +86,7 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
func testAndRunTxs(app *GaiaApp) []simulation.Operation { func testAndRunTxs(app *GaiaApp) []simulation.Operation {
return []simulation.Operation{ return []simulation.Operation{
banksim.TestAndRunSingleInputMsgSend(app.accountMapper), banksim.SimulateSingleInputMsgSend(app.accountMapper),
govsim.SimulateMsgSubmitProposal(app.govKeeper, app.stakeKeeper), govsim.SimulateMsgSubmitProposal(app.govKeeper, app.stakeKeeper),
govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper), govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper),
govsim.SimulateMsgVote(app.govKeeper, app.stakeKeeper), govsim.SimulateMsgVote(app.govKeeper, app.stakeKeeper),
@ -171,11 +170,10 @@ func TestAppStateDeterminism(t *testing.T) {
true, true,
) )
appHash := app.LastCommitID().Hash appHash := app.LastCommitID().Hash
fmt.Printf(">>> APP HASH: %v, %X\n", appHash, appHash)
appHashList[j] = appHash appHashList[j] = appHash
} }
for k := 1; k < numTimesToRunPerSeed; k++ { for k := 1; k < numTimesToRunPerSeed; k++ {
require.Equal(t, appHashList[0], appHashList[k]) require.Equal(t, appHashList[0], appHashList[k], "appHash list: %v", appHashList)
} }
} }
} }

View File

@ -18,10 +18,10 @@ import (
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
) )
// TestAndRunSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both // SimulateSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both
// accounts already exist. // accounts already exist.
func TestAndRunSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation { func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOps []simulation.FutureOperation, err sdk.Error) {
fromKey := simulation.RandomKey(r, keys) fromKey := simulation.RandomKey(r, keys)
fromAddr := sdk.AccAddress(fromKey.PubKey().Address()) fromAddr := sdk.AccAddress(fromKey.PubKey().Address())
toKey := simulation.RandomKey(r, keys) toKey := simulation.RandomKey(r, keys)
@ -36,13 +36,13 @@ func TestAndRunSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operatio
initFromCoins := mapper.GetAccount(ctx, fromAddr).GetCoins() initFromCoins := mapper.GetAccount(ctx, fromAddr).GetCoins()
if len(initFromCoins) == 0 { if len(initFromCoins) == 0 {
return "skipping, no coins at all", nil return "skipping, no coins at all", nil, nil
} }
denomIndex := r.Intn(len(initFromCoins)) denomIndex := r.Intn(len(initFromCoins))
amt, goErr := randPositiveInt(r, initFromCoins[denomIndex].Amount) amt, goErr := randPositiveInt(r, initFromCoins[denomIndex].Amount)
if goErr != nil { if goErr != nil {
return "skipping bank send due to account having no coins of denomination " + initFromCoins[denomIndex].Denom, nil return "skipping bank send due to account having no coins of denomination " + initFromCoins[denomIndex].Denom, nil, nil
} }
action = fmt.Sprintf("%s is sending %s %s to %s", action = fmt.Sprintf("%s is sending %s %s to %s",
@ -61,7 +61,7 @@ func TestAndRunSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operatio
sendAndVerifyMsgSend(t, app, mapper, msg, ctx, log, []crypto.PrivKey{fromKey}) sendAndVerifyMsgSend(t, app, mapper, msg, ctx, log, []crypto.PrivKey{fromKey})
event("bank/sendAndVerifyMsgSend/ok") event("bank/sendAndVerifyMsgSend/ok")
return action, nil return action, nil, nil
} }
} }

View File

@ -34,7 +34,7 @@ func TestBankWithRandomMessages(t *testing.T) {
simulation.Simulate( simulation.Simulate(
t, mapp.BaseApp, appStateFn, t, mapp.BaseApp, appStateFn,
[]simulation.Operation{ []simulation.Operation{
TestAndRunSingleInputMsgSend(mapper), SimulateSingleInputMsgSend(mapper),
}, },
[]simulation.RandSetup{}, []simulation.RandSetup{},
[]simulation.Invariant{ []simulation.Invariant{

View File

@ -20,9 +20,10 @@ const (
denom = "steak" denom = "steak"
) )
// SimulateMsgSubmitProposal // SimulateMsgSubmitProposal simulates a msg Submit Proposal
// Note: Currently doesn't ensure that the proposal txt is in JSON form
func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation { func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOps []simulation.FutureOperation, err sdk.Error) {
key := simulation.RandomKey(r, keys) key := simulation.RandomKey(r, keys)
addr := sdk.AccAddress(key.PubKey().Address()) addr := sdk.AccAddress(key.PubKey().Address())
deposit := randomDeposit(r) deposit := randomDeposit(r)
@ -45,18 +46,18 @@ func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operati
} }
event(fmt.Sprintf("gov/MsgSubmitProposal/%v", result.IsOK())) event(fmt.Sprintf("gov/MsgSubmitProposal/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgSubmitProposal: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgSubmitProposal: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }
// SimulateMsgDeposit // SimulateMsgDeposit
func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation { func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, 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) {
key := simulation.RandomKey(r, keys) key := simulation.RandomKey(r, keys)
addr := sdk.AccAddress(key.PubKey().Address()) addr := sdk.AccAddress(key.PubKey().Address())
proposalID, ok := randomProposalID(r, k, ctx) proposalID, ok := randomProposalID(r, k, ctx)
if !ok { if !ok {
return "no-operation", nil return "no-operation", nil, nil
} }
deposit := randomDeposit(r) deposit := randomDeposit(r)
msg := gov.NewMsgDeposit(addr, proposalID, deposit) msg := gov.NewMsgDeposit(addr, proposalID, deposit)
@ -72,18 +73,18 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
} }
event(fmt.Sprintf("gov/MsgDeposit/%v", result.IsOK())) event(fmt.Sprintf("gov/MsgDeposit/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgDeposit: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgDeposit: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }
// SimulateMsgVote // SimulateMsgVote
func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation { func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, 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) {
key := simulation.RandomKey(r, keys) key := simulation.RandomKey(r, keys)
addr := sdk.AccAddress(key.PubKey().Address()) addr := sdk.AccAddress(key.PubKey().Address())
proposalID, ok := randomProposalID(r, k, ctx) proposalID, ok := randomProposalID(r, k, ctx)
if !ok { if !ok {
return "no-operation", nil return "no-operation", nil, nil
} }
option := randomVotingOption(r) option := randomVotingOption(r)
msg := gov.NewMsgVote(addr, proposalID, option) msg := gov.NewMsgVote(addr, proposalID, option)
@ -95,7 +96,7 @@ func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
} }
event(fmt.Sprintf("gov/MsgVote/%v", result.IsOK())) event(fmt.Sprintf("gov/MsgVote/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgVote: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgVote: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }

View File

@ -70,6 +70,8 @@ func SimulateFromSeed(
request := abci.RequestBeginBlock{Header: header} request := abci.RequestBeginBlock{Header: header}
var pastTimes []time.Time 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++ { for i := 0; i < numBlocks; i++ {
@ -96,9 +98,14 @@ func SimulateFromSeed(
default: default:
thisBlockSize = r.Intn(blockSize * 4) 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++ { 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 log += "\n" + logUpdate
queueOperations(operationQueue, futureOps)
require.Nil(t, err, log) require.Nil(t, err, log)
if onOperation { if onOperation {
@ -134,6 +141,39 @@ func SimulateFromSeed(
DisplayEvents(events) 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 { func getKeys(validators map[string]mockValidator) []string {
keys := make([]string, len(validators)) keys := make([]string, len(validators))
i := 0 i := 0

View File

@ -19,10 +19,13 @@ type (
// For ease of debugging, // For ease of debugging,
// an operation returns a descriptive message "action", // an operation returns a descriptive message "action",
// which details what this fuzzed state machine transition actually did. // 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( Operation func(
t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
privKeys []crypto.PrivKey, log string, event func(string), 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 performs the random setup the mock module needs.
RandSetup func(r *rand.Rand, privKeys []crypto.PrivKey) RandSetup func(r *rand.Rand, privKeys []crypto.PrivKey)
@ -36,6 +39,15 @@ type (
val abci.Validator val abci.Validator
livenessState int 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 // PeriodicInvariant returns an Invariant function closure that asserts

View File

@ -17,7 +17,7 @@ import (
// SimulateMsgUnjail // SimulateMsgUnjail
func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation { func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, 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) {
key := simulation.RandomKey(r, keys) key := simulation.RandomKey(r, keys)
address := sdk.AccAddress(key.PubKey().Address()) address := sdk.AccAddress(key.PubKey().Address())
msg := slashing.NewMsgUnjail(address) msg := slashing.NewMsgUnjail(address)
@ -29,6 +29,6 @@ func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation {
} }
event(fmt.Sprintf("slashing/MsgUnjail/%v", result.IsOK())) event(fmt.Sprintf("slashing/MsgUnjail/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgUnjail: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgUnjail: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }

View File

@ -19,7 +19,7 @@ import (
// SimulateMsgCreateValidator // SimulateMsgCreateValidator
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation { func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, 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 denom := k.GetParams(ctx).BondDenom
description := stake.Description{ description := stake.Description{
Moniker: simulation.RandStringOfLength(r, 10), Moniker: simulation.RandStringOfLength(r, 10),
@ -32,7 +32,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
amount = simulation.RandomAmount(r, amount) amount = simulation.RandomAmount(r, amount)
} }
if amount.Equal(sdk.ZeroInt()) { if amount.Equal(sdk.ZeroInt()) {
return "no-operation", nil return "no-operation", nil, nil
} }
msg := stake.MsgCreateValidator{ msg := stake.MsgCreateValidator{
Description: description, Description: description,
@ -50,13 +50,13 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
event(fmt.Sprintf("stake/MsgCreateValidator/%v", result.IsOK())) event(fmt.Sprintf("stake/MsgCreateValidator/%v", result.IsOK()))
// require.True(t, result.IsOK(), "expected OK result but instead got %v", result) // require.True(t, result.IsOK(), "expected OK result but instead got %v", result)
action = fmt.Sprintf("TestMsgCreateValidator: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgCreateValidator: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }
// SimulateMsgEditValidator // SimulateMsgEditValidator
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation { func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, 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{ description := stake.Description{
Moniker: simulation.RandStringOfLength(r, 10), Moniker: simulation.RandStringOfLength(r, 10),
Identity: simulation.RandStringOfLength(r, 10), Identity: simulation.RandStringOfLength(r, 10),
@ -78,13 +78,13 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
} }
event(fmt.Sprintf("stake/MsgEditValidator/%v", result.IsOK())) event(fmt.Sprintf("stake/MsgEditValidator/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgEditValidator: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgEditValidator: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }
// SimulateMsgDelegate // SimulateMsgDelegate
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation { func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, 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 denom := k.GetParams(ctx).BondDenom
validatorKey := simulation.RandomKey(r, keys) validatorKey := simulation.RandomKey(r, keys)
validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address()) validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address())
@ -95,7 +95,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
amount = simulation.RandomAmount(r, amount) amount = simulation.RandomAmount(r, amount)
} }
if amount.Equal(sdk.ZeroInt()) { if amount.Equal(sdk.ZeroInt()) {
return "no-operation", nil return "no-operation", nil, nil
} }
msg := stake.MsgDelegate{ msg := stake.MsgDelegate{
DelegatorAddr: delegatorAddress, DelegatorAddr: delegatorAddress,
@ -110,13 +110,13 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
} }
event(fmt.Sprintf("stake/MsgDelegate/%v", result.IsOK())) event(fmt.Sprintf("stake/MsgDelegate/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgDelegate: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgDelegate: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }
// SimulateMsgBeginUnbonding // SimulateMsgBeginUnbonding
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation { func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, 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 denom := k.GetParams(ctx).BondDenom
validatorKey := simulation.RandomKey(r, keys) validatorKey := simulation.RandomKey(r, keys)
validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address()) validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address())
@ -127,7 +127,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
amount = simulation.RandomAmount(r, amount) amount = simulation.RandomAmount(r, amount)
} }
if amount.Equal(sdk.ZeroInt()) { if amount.Equal(sdk.ZeroInt()) {
return "no-operation", nil return "no-operation", nil, nil
} }
msg := stake.MsgBeginUnbonding{ msg := stake.MsgBeginUnbonding{
DelegatorAddr: delegatorAddress, DelegatorAddr: delegatorAddress,
@ -142,13 +142,13 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
} }
event(fmt.Sprintf("stake/MsgBeginUnbonding/%v", result.IsOK())) event(fmt.Sprintf("stake/MsgBeginUnbonding/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgBeginUnbonding: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgBeginUnbonding: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }
// SimulateMsgCompleteUnbonding // SimulateMsgCompleteUnbonding
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation { func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, 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) validatorKey := simulation.RandomKey(r, keys)
validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address()) validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address())
delegatorKey := simulation.RandomKey(r, keys) delegatorKey := simulation.RandomKey(r, keys)
@ -165,13 +165,13 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
} }
event(fmt.Sprintf("stake/MsgCompleteUnbonding/%v", result.IsOK())) event(fmt.Sprintf("stake/MsgCompleteUnbonding/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgCompleteUnbonding: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgCompleteUnbonding: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }
// SimulateMsgBeginRedelegate // SimulateMsgBeginRedelegate
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation { func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, 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 denom := k.GetParams(ctx).BondDenom
sourceValidatorKey := simulation.RandomKey(r, keys) sourceValidatorKey := simulation.RandomKey(r, keys)
sourceValidatorAddress := sdk.AccAddress(sourceValidatorKey.PubKey().Address()) sourceValidatorAddress := sdk.AccAddress(sourceValidatorKey.PubKey().Address())
@ -185,7 +185,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
amount = simulation.RandomAmount(r, amount) amount = simulation.RandomAmount(r, amount)
} }
if amount.Equal(sdk.ZeroInt()) { if amount.Equal(sdk.ZeroInt()) {
return "no-operation", nil return "no-operation", nil, nil
} }
msg := stake.MsgBeginRedelegate{ msg := stake.MsgBeginRedelegate{
DelegatorAddr: delegatorAddress, DelegatorAddr: delegatorAddress,
@ -201,13 +201,13 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
} }
event(fmt.Sprintf("stake/MsgBeginRedelegate/%v", result.IsOK())) event(fmt.Sprintf("stake/MsgBeginRedelegate/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgBeginRedelegate: %s", msg.GetSignBytes()) action = fmt.Sprintf("TestMsgBeginRedelegate: %s", msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }
// SimulateMsgCompleteRedelegate // SimulateMsgCompleteRedelegate
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation { func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, err sdk.Error) { return func(t *testing.T, 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) validatorSrcKey := simulation.RandomKey(r, keys)
validatorSrcAddress := sdk.AccAddress(validatorSrcKey.PubKey().Address()) validatorSrcAddress := sdk.AccAddress(validatorSrcKey.PubKey().Address())
validatorDstKey := simulation.RandomKey(r, keys) validatorDstKey := simulation.RandomKey(r, keys)
@ -227,7 +227,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
} }
event(fmt.Sprintf("stake/MsgCompleteRedelegate/%v", result.IsOK())) event(fmt.Sprintf("stake/MsgCompleteRedelegate/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgCompleteRedelegate: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgCompleteRedelegate: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil return action, nil, nil
} }
} }