From 3cffe29da7086ca93dabbcbf993e860777146ef0 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 1 Nov 2018 11:58:25 -0700 Subject: [PATCH 1/2] simulation: Make validator choice use validator set This also had to change the default seed, since with the previous one it actually got into a state where there were no validators left bonded, lol. This also changes Unbond msgs from failing with almost 100% probability to now only failing with 33% probability. Thus more of the state machine is getting tested! --- Makefile | 2 +- x/mock/simulation/util.go | 7 ++++++ x/stake/keeper/test_common.go | 15 +++++++++++++ x/stake/simulation/msgs.go | 40 ++++++++++++++++++----------------- 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 9d4ad0a25..af4ea71c9 100644 --- a/Makefile +++ b/Makefile @@ -169,7 +169,7 @@ test_sim_gaia_nondeterminism: test_sim_gaia_fast: @echo "Running quick Gaia simulation. This may take several minutes..." - @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=500 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=9 -v -timeout 24h + @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=500 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=10 -v -timeout 24h test_sim_gaia_multi_seed: @echo "Running multi-seed Gaia simulation. This may take awhile!" diff --git a/x/mock/simulation/util.go b/x/mock/simulation/util.go index 84a4ad2a3..d5a20b6e8 100644 --- a/x/mock/simulation/util.go +++ b/x/mock/simulation/util.go @@ -2,6 +2,7 @@ package simulation import ( "fmt" + "math/big" "math/rand" "os" "sort" @@ -71,6 +72,12 @@ func RandomAmount(r *rand.Rand, max sdk.Int) sdk.Int { return sdk.NewInt(int64(r.Intn(int(max.Int64())))) } +// RandomDecAmount generates a random decimal amount +func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec { + randInt := big.NewInt(0).Rand(r, max.Int) + return sdk.NewDecFromBigIntWithPrec(randInt, sdk.Precision) +} + // RandomAccounts generates n random accounts func RandomAccounts(r *rand.Rand, n int) []Account { accs := make([]Account, n) diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 7978f17e9..af7e688f3 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -3,6 +3,7 @@ package keeper import ( "bytes" "encoding/hex" + "math/rand" "strconv" "testing" @@ -215,3 +216,17 @@ func validatorByPowerIndexExists(k Keeper, ctx sdk.Context, power []byte) bool { store := ctx.KVStore(k.storeKey) return store.Has(power) } + +// RandomValidator returns a random validator given access to the keeper and ctx +func RandomValidator(r *rand.Rand, keeper Keeper, ctx sdk.Context) types.Validator { + vals := keeper.GetAllValidators(ctx) + i := r.Intn(len(vals)) + return vals[i] +} + +// RandomBondedValidator returns a random bonded validator given access to the keeper and ctx +func RandomBondedValidator(r *rand.Rand, keeper Keeper, ctx sdk.Context) types.Validator { + vals := keeper.GetBondedValidatorsByPower(ctx) + i := r.Intn(len(vals)) + return vals[i] +} diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index 8684126e3..ec2dffd92 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/mock/simulation" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/keeper" abci "github.com/tendermint/tendermint/abci/types" ) @@ -87,8 +88,8 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation { maxCommission := sdk.NewInt(10) newCommissionRate := sdk.NewDecWithPrec(simulation.RandomAmount(r, maxCommission).Int64(), 1) - acc := simulation.RandomAcc(r, accs) - address := sdk.ValAddress(acc.Address) + val := keeper.RandomValidator(r, k, ctx) + address := val.GetOperator() msg := stake.MsgEditValidator{ Description: description, ValidatorAddr: address, @@ -118,8 +119,8 @@ func SimulateMsgDelegate(m auth.AccountKeeper, k stake.Keeper) simulation.Operat action string, fOp []simulation.FutureOperation, err error) { denom := k.GetParams(ctx).BondDenom - validatorAcc := simulation.RandomAcc(r, accs) - validatorAddress := sdk.ValAddress(validatorAcc.Address) + val := keeper.RandomValidator(r, k, ctx) + validatorAddress := val.GetOperator() delegatorAcc := simulation.RandomAcc(r, accs) delegatorAddress := delegatorAcc.Address amount := m.GetAccount(ctx, delegatorAddress).GetCoins().AmountOf(denom) @@ -155,25 +156,26 @@ func SimulateMsgBeginUnbonding(m auth.AccountKeeper, k stake.Keeper) simulation. accs []simulation.Account, event func(string)) ( action string, fOp []simulation.FutureOperation, err error) { - denom := k.GetParams(ctx).BondDenom - validatorAcc := simulation.RandomAcc(r, accs) - validatorAddress := sdk.ValAddress(validatorAcc.Address) delegatorAcc := simulation.RandomAcc(r, accs) delegatorAddress := delegatorAcc.Address - amount := m.GetAccount(ctx, delegatorAddress).GetCoins().AmountOf(denom) - if amount.GT(sdk.ZeroInt()) { - amount = simulation.RandomAmount(r, amount) + delegations := k.GetAllDelegatorDelegations(ctx, delegatorAddress) + if len(delegations) == 0 { + return "no-operation", nil, nil } - if amount.Equal(sdk.ZeroInt()) { + delegation := delegations[r.Intn(len(delegations))] + + numShares := simulation.RandomDecAmount(r, delegation.Shares) + if numShares.Equal(sdk.ZeroDec()) { return "no-operation", nil, nil } msg := stake.MsgBeginUnbonding{ DelegatorAddr: delegatorAddress, - ValidatorAddr: validatorAddress, - SharesAmount: sdk.NewDecFromInt(amount), + ValidatorAddr: delegation.ValidatorAddr, + SharesAmount: numShares, } if msg.ValidateBasic() != nil { - return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) + return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s, got error %v", + msg.GetSignBytes(), msg.ValidateBasic()) } ctx, write := ctx.CacheContext() result := handler(ctx, msg) @@ -194,10 +196,10 @@ func SimulateMsgBeginRedelegate(m auth.AccountKeeper, k stake.Keeper) simulation action string, fOp []simulation.FutureOperation, err error) { denom := k.GetParams(ctx).BondDenom - sourceValidatorAcc := simulation.RandomAcc(r, accs) - sourceValidatorAddress := sdk.ValAddress(sourceValidatorAcc.Address) - destValidatorAcc := simulation.RandomAcc(r, accs) - destValidatorAddress := sdk.ValAddress(destValidatorAcc.Address) + srcVal := keeper.RandomValidator(r, k, ctx) + srcValidatorAddress := srcVal.GetOperator() + destVal := keeper.RandomValidator(r, k, ctx) + destValidatorAddress := destVal.GetOperator() delegatorAcc := simulation.RandomAcc(r, accs) delegatorAddress := delegatorAcc.Address // TODO @@ -210,7 +212,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountKeeper, k stake.Keeper) simulation } msg := stake.MsgBeginRedelegate{ DelegatorAddr: delegatorAddress, - ValidatorSrcAddr: sourceValidatorAddress, + ValidatorSrcAddr: srcValidatorAddress, ValidatorDstAddr: destValidatorAddress, SharesAmount: sdk.NewDecFromInt(amount), } From 52083e105b37b7686ce50ae3c275942a91d5c3ef Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 1 Nov 2018 12:52:03 -0700 Subject: [PATCH 2/2] Update changelog --- PENDING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PENDING.md b/PENDING.md index 8a16136c0..2606aa0ff 100644 --- a/PENDING.md +++ b/PENDING.md @@ -41,7 +41,8 @@ IMPROVEMENTS * SDK - #2573 [x/distribution] add accum invariance - - \#1924 [simulation] Use a transition matrix for block size + - \#1924 [x/mock/simulation] Use a transition matrix for block size + - \#2660 [x/mock/simulation] Staking transactions get tested far more frequently - #2610 [x/stake] Block redelegation to and from the same validator