From 3e148a9ce7a33b83f74c0abbb4ecf59529b1f96a Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Mon, 24 Aug 2020 12:55:42 +0200 Subject: [PATCH] fix hardcoded auth sims (#7135) * fix hardcoded auth sims * changelog Co-authored-by: Alexander Bezobchuk Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- CHANGELOG.md | 1 + simapp/app.go | 9 ++-- simapp/sim_bench_test.go | 19 +++++-- simapp/sim_test.go | 48 ++++++++++++++---- types/simulation/types.go | 3 ++ x/auth/module.go | 14 +++--- x/auth/simulation/genesis.go | 84 ++++++++++++++++--------------- x/auth/simulation/genesis_test.go | 2 +- x/bank/simulation/genesis.go | 2 +- x/simulation/simulate.go | 13 +++-- 10 files changed, 124 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 767fb0991..46b7dcf58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -186,6 +186,7 @@ be used to retrieve the actual proposal `Content`. Also the `NewMsgSubmitProposa ### Bug Fixes +* (simulation) [\#7129](https://github.com/cosmos/cosmos-sdk/issues/7129) Fix support for custom `Account` and key types on auth's simulation. * (types) [\#7084](https://github.com/cosmos/cosmos-sdk/pull/7084) Fix panic when calling `BigInt()` on an uninitialized `Int`. * (x/bank) [\#6536](https://github.com/cosmos/cosmos-sdk/pull/6536) Fix bug in `WriteGeneratedTxResponse` function used by multiple REST endpoints. Now it writes a Tx in StdTx format. diff --git a/simapp/app.go b/simapp/app.go index fc6cda4c7..3d0bd699a 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -25,6 +25,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/ante" authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/bank" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" @@ -291,7 +292,7 @@ func NewSimApp( app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx, encodingConfig.TxConfig, ), - auth.NewAppModule(appCodec, app.AccountKeeper), + auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), capability.NewAppModule(appCodec, *app.CapabilityKeeper), crisis.NewAppModule(&app.CrisisKeeper), @@ -317,7 +318,7 @@ func NewSimApp( ) app.mm.SetOrderEndBlockers(crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName) - // NOTE: The genutils moodule must occur after staking so that pools are + // NOTE: The genutils module must occur after staking so that pools are // properly initialized with tokens from genesis accounts. // NOTE: Capability module must occur first so that it can initialize any capabilities // so that other modules that want to create or claim capabilities afterwards in InitChain @@ -340,7 +341,7 @@ func NewSimApp( // NOTE: this is not required apps that don't use the simulator for fuzz testing // transactions app.sm = module.NewSimulationManager( - auth.NewAppModule(appCodec, app.AccountKeeper), + auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), capability.NewAppModule(appCodec, *app.CapabilityKeeper), gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), @@ -446,7 +447,7 @@ func (app *SimApp) BlockedAddrs() map[string]bool { return blockedAddrs } -// Codec returns SimApp's codec. +// LegacyAmino returns SimApp's amino codec. // // NOTE: This is solely to be used for testing purposes as it may be desirable // for modules to register their own custom testing types. diff --git a/simapp/sim_bench_test.go b/simapp/sim_bench_test.go index ed9777003..97ab48135 100644 --- a/simapp/sim_bench_test.go +++ b/simapp/sim_bench_test.go @@ -7,6 +7,7 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" ) @@ -30,9 +31,14 @@ func BenchmarkFullAppSimulation(b *testing.B) { // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( - b, os.Stdout, app.BaseApp, AppStateFn(app.AppCodec(), app.SimulationManager()), + b, + os.Stdout, + app.BaseApp, + AppStateFn(app.AppCodec(), app.SimulationManager()), + simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 SimulationOperations(app, app.AppCodec(), config), - app.ModuleAccountAddrs(), config, + app.ModuleAccountAddrs(), + config, ) // export state and simParams before the simulation error is checked @@ -69,9 +75,14 @@ func BenchmarkInvariants(b *testing.B) { // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( - b, os.Stdout, app.BaseApp, AppStateFn(app.AppCodec(), app.SimulationManager()), + b, + os.Stdout, + app.BaseApp, + AppStateFn(app.AppCodec(), app.SimulationManager()), + simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 SimulationOperations(app, app.AppCodec(), config), - app.ModuleAccountAddrs(), config, + app.ModuleAccountAddrs(), + config, ) // export state and simParams before the simulation error is checked diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 6428e1a65..49bdf801d 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp/helpers" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" @@ -72,9 +73,14 @@ func TestFullAppSimulation(t *testing.T) { // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( - t, os.Stdout, app.BaseApp, AppStateFn(app.AppCodec(), app.SimulationManager()), + t, + os.Stdout, + app.BaseApp, + AppStateFn(app.AppCodec(), app.SimulationManager()), + simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 SimulationOperations(app, app.AppCodec(), config), - app.ModuleAccountAddrs(), config, + app.ModuleAccountAddrs(), + config, ) // export state and simParams before the simulation error is checked @@ -104,9 +110,14 @@ func TestAppImportExport(t *testing.T) { // Run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( - t, os.Stdout, app.BaseApp, AppStateFn(app.AppCodec(), app.SimulationManager()), + t, + os.Stdout, + app.BaseApp, + AppStateFn(app.AppCodec(), app.SimulationManager()), + simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 SimulationOperations(app, app.AppCodec(), config), - app.ModuleAccountAddrs(), config, + app.ModuleAccountAddrs(), + config, ) // export state and simParams before the simulation error is checked @@ -195,9 +206,14 @@ func TestAppSimulationAfterImport(t *testing.T) { // Run randomized simulation stopEarly, simParams, simErr := simulation.SimulateFromSeed( - t, os.Stdout, app.BaseApp, AppStateFn(app.AppCodec(), app.SimulationManager()), + t, + os.Stdout, + app.BaseApp, + AppStateFn(app.AppCodec(), app.SimulationManager()), + simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 SimulationOperations(app, app.AppCodec(), config), - app.ModuleAccountAddrs(), config, + app.ModuleAccountAddrs(), + config, ) // export state and simParams before the simulation error is checked @@ -237,9 +253,14 @@ func TestAppSimulationAfterImport(t *testing.T) { }) _, _, err = simulation.SimulateFromSeed( - t, os.Stdout, newApp.BaseApp, AppStateFn(app.AppCodec(), app.SimulationManager()), - SimulationOperations(newApp, newApp.AppCodec(), config), - newApp.ModuleAccountAddrs(), config, + t, + os.Stdout, + app.BaseApp, + AppStateFn(app.AppCodec(), app.SimulationManager()), + simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 + SimulationOperations(app, app.AppCodec(), config), + app.ModuleAccountAddrs(), + config, ) require.NoError(t, err) } @@ -282,9 +303,14 @@ func TestAppStateDeterminism(t *testing.T) { ) _, _, err := simulation.SimulateFromSeed( - t, os.Stdout, app.BaseApp, AppStateFn(app.AppCodec(), app.SimulationManager()), + t, + os.Stdout, + app.BaseApp, + AppStateFn(app.AppCodec(), app.SimulationManager()), + simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 SimulationOperations(app, app.AppCodec(), config), - app.ModuleAccountAddrs(), config, + app.ModuleAccountAddrs(), + config, ) require.NoError(t, err) diff --git a/types/simulation/types.go b/types/simulation/types.go index 0474d6163..8778611af 100644 --- a/types/simulation/types.go +++ b/types/simulation/types.go @@ -153,6 +153,9 @@ type AppStateFn func(r *rand.Rand, accs []Account, config Config) ( appState json.RawMessage, accounts []Account, chainId string, genesisTimestamp time.Time, ) +// RandomAccountFn returns a slice of n random simulation accounts +type RandomAccountFn func(r *rand.Rand, n int) []Account + type Params interface { PastEvidenceFraction() float64 NumKeys() int diff --git a/x/auth/module.go b/x/auth/module.go index 96b096ae5..c83169380 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -85,14 +85,16 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) type AppModule struct { AppModuleBasic - accountKeeper keeper.AccountKeeper + accountKeeper keeper.AccountKeeper + randGenAccountsFn simulation.RandomGenesisAccountsFn } // NewAppModule creates a new AppModule object -func NewAppModule(cdc codec.Marshaler, accountKeeper keeper.AccountKeeper) AppModule { +func NewAppModule(cdc codec.Marshaler, accountKeeper keeper.AccountKeeper, randGenAccountsFn simulation.RandomGenesisAccountsFn) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - accountKeeper: accountKeeper, + AppModuleBasic: AppModuleBasic{}, + accountKeeper: accountKeeper, + randGenAccountsFn: randGenAccountsFn, } } @@ -153,8 +155,8 @@ func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.Validato // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the auth module -func (AppModule) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) +func (am AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState, am.randGenAccountsFn) } // ProposalContents doesn't return any content functions for governance proposals. diff --git a/x/auth/simulation/genesis.go b/x/auth/simulation/genesis.go index e1b3b293a..98148cb6c 100644 --- a/x/auth/simulation/genesis.go +++ b/x/auth/simulation/genesis.go @@ -1,7 +1,5 @@ package simulation -// DONTCOVER - import ( "fmt" "math/rand" @@ -23,6 +21,48 @@ const ( SigVerifyCostSECP256K1 = "sig_verify_cost_secp256k1" ) +// RandomGenesisAccountsFn defines the function required to generate custom account types +// on the auth module simulation. +type RandomGenesisAccountsFn func(simState *module.SimulationState) types.GenesisAccounts + +// RandomGenesisAccounts defines the default RandomGenesisAccountsFn used on the SDK. +// It creates a slice of BaseAccount, ContinuousVestingAccount and DelayedVestingAccount. +func RandomGenesisAccounts(simState *module.SimulationState) types.GenesisAccounts { + genesisAccs := make(types.GenesisAccounts, len(simState.Accounts)) + for i, acc := range simState.Accounts { + bacc := types.NewBaseAccountWithAddress(acc.Address) + + // Only consider making a vesting account once the initial bonded validator + // set is exhausted due to needing to track DelegatedVesting. + if !(int64(i) > simState.NumBonded && simState.Rand.Intn(100) < 50) { + genesisAccs[i] = bacc + continue + } + + initialVesting := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, simState.Rand.Int63n(simState.InitialStake))) + var endTime int64 + + startTime := simState.GenTimestamp.Unix() + + // Allow for some vesting accounts to vest very quickly while others very slowly. + if simState.Rand.Intn(100) < 50 { + endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime)+1, int(startTime+(60*60*24*30)))) + } else { + endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime)+1, int(startTime+(60*60*12)))) + } + + bva := vestingtypes.NewBaseVestingAccount(bacc, initialVesting, endTime) + + if simState.Rand.Intn(100) < 50 { + genesisAccs[i] = vestingtypes.NewContinuousVestingAccountRaw(bva, startTime) + } else { + genesisAccs[i] = vestingtypes.NewDelayedVestingAccountRaw(bva) + } + } + + return genesisAccs +} + // GenMaxMemoChars randomized MaxMemoChars func GenMaxMemoChars(r *rand.Rand) uint64 { return uint64(simulation.RandIntBetween(r, 100, 200)) @@ -52,7 +92,7 @@ func GenSigVerifyCostSECP256K1(r *rand.Rand) uint64 { } // RandomizedGenState generates a random GenesisState for auth -func RandomizedGenState(simState *module.SimulationState) { +func RandomizedGenState(simState *module.SimulationState, randGenAccountsFn RandomGenesisAccountsFn) { var maxMemoChars uint64 simState.AppParams.GetOrGenerate( simState.Cdc, MaxMemoChars, &maxMemoChars, simState.Rand, @@ -85,46 +125,10 @@ func RandomizedGenState(simState *module.SimulationState) { params := types.NewParams(maxMemoChars, txSigLimit, txSizeCostPerByte, sigVerifyCostED25519, sigVerifyCostSECP256K1) - genesisAccs := RandomGenesisAccounts(simState) + genesisAccs := randGenAccountsFn(simState) authGenesis := types.NewGenesisState(params, genesisAccs) fmt.Printf("Selected randomly generated auth parameters:\n%s\n", codec.MustMarshalJSONIndent(simState.Cdc, &authGenesis.Params)) simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(authGenesis) } - -// RandomGenesisAccounts returns randomly generated genesis accounts -func RandomGenesisAccounts(simState *module.SimulationState) (genesisAccs types.GenesisAccounts) { - for i, acc := range simState.Accounts { - bacc := types.NewBaseAccountWithAddress(acc.Address) - var gacc types.GenesisAccount = bacc - - // Only consider making a vesting account once the initial bonded validator - // set is exhausted due to needing to track DelegatedVesting. - if int64(i) > simState.NumBonded && simState.Rand.Intn(100) < 50 { - initialVesting := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, simState.Rand.Int63n(simState.InitialStake))) - var endTime int64 - - startTime := simState.GenTimestamp.Unix() - - // Allow for some vesting accounts to vest very quickly while others very slowly. - if simState.Rand.Intn(100) < 50 { - endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime)+1, int(startTime+(60*60*24*30)))) - } else { - endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime)+1, int(startTime+(60*60*12)))) - } - - bva := vestingtypes.NewBaseVestingAccount(bacc, initialVesting, endTime) - - if simState.Rand.Intn(100) < 50 { - gacc = vestingtypes.NewContinuousVestingAccountRaw(bva, startTime) - } else { - gacc = vestingtypes.NewDelayedVestingAccountRaw(bva) - } - } - - genesisAccs = append(genesisAccs, gacc) - } - - return genesisAccs -} diff --git a/x/auth/simulation/genesis_test.go b/x/auth/simulation/genesis_test.go index e0ae05f87..8894010d6 100644 --- a/x/auth/simulation/genesis_test.go +++ b/x/auth/simulation/genesis_test.go @@ -35,7 +35,7 @@ func TestRandomizedGenState(t *testing.T) { GenState: make(map[string]json.RawMessage), } - simulation.RandomizedGenState(&simState) + simulation.RandomizedGenState(&simState, simulation.RandomGenesisAccounts) var authGenesis types.GenesisState simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &authGenesis) diff --git a/x/bank/simulation/genesis.go b/x/bank/simulation/genesis.go index 61a289328..21b298d63 100644 --- a/x/bank/simulation/genesis.go +++ b/x/bank/simulation/genesis.go @@ -35,7 +35,7 @@ func RandomGenesisSendParams(r *rand.Rand) types.SendEnabledParams { return params.SendEnabled } -// RandomGenesisAccounts returns a slice of account balances. Each account has +// RandomGenesisBalances returns a slice of account balances. Each account has // a balance of simState.InitialStake for sdk.DefaultBondDenom. func RandomGenesisBalances(simState *module.SimulationState) []types.Balance { genesisBalances := []types.Balance{} diff --git a/x/simulation/simulate.go b/x/simulation/simulate.go index 5d6e155a7..d0ee64bbe 100644 --- a/x/simulation/simulate.go +++ b/x/simulation/simulate.go @@ -44,9 +44,14 @@ func initChain( // operations, testing the provided invariants, but using the provided config.Seed. // TODO: split this monster function up func SimulateFromSeed( - tb testing.TB, w io.Writer, app *baseapp.BaseApp, - appStateFn simulation.AppStateFn, ops WeightedOperations, - blackListedAccs map[string]bool, config simulation.Config, + tb testing.TB, + w io.Writer, + app *baseapp.BaseApp, + appStateFn simulation.AppStateFn, + randAccFn simulation.RandomAccountFn, + ops WeightedOperations, + blackListedAccs map[string]bool, + config simulation.Config, ) (stopEarly bool, exportedParams Params, err error) { // in case we have to end early, don't os.Exit so that we can run cleanup code. testingMode, _, b := getTestingMode(tb) @@ -57,7 +62,7 @@ func SimulateFromSeed( fmt.Fprintf(w, "Randomized simulation params: \n%s\n", mustMarshalJSONIndent(params)) timeDiff := maxTimePerBlock - minTimePerBlock - accs := simulation.RandomAccounts(r, params.NumKeys()) + accs := randAccFn(r, params.NumKeys()) eventStats := NewEventStats() // Second variable to keep pending validator set (delayed one block since