From 2a7f4e4343d1b379e52c72ce322d3c2ba817efc2 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Thu, 9 Feb 2023 15:16:07 +0100 Subject: [PATCH] refactor!: extract `AppStateFn` out of simapp (#14977) --- CHANGELOG.md | 1 + crypto/keys/secp256k1/secp256k1_test.go | 2 +- simapp/app_v2.go | 2 +- simapp/params/params.go | 7 -- simapp/sim_bench_test.go | 4 +- simapp/sim_test.go | 10 +-- .../sims/state_helpers.go | 70 +++++++++++-------- 7 files changed, 50 insertions(+), 46 deletions(-) delete mode 100644 simapp/params/params.go rename simapp/state.go => testutil/sims/state_helpers.go (80%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c5183f62c77..e808f085da0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -174,6 +174,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* (simapp) [#14977](https://github.com/cosmos/cosmos-sdk/pull/14977) Move simulation helpers functions (`AppStateFn` and `AppStateRandomizedFn`) to `testutil/sims`. These takes an extra genesisState argument which is the default state of the app. * (x/gov) [#14720](https://github.com/cosmos/cosmos-sdk/pull/14720) Add an expedited field in the gov v1 proposal and `MsgNewMsgProposal`. * [#14847](https://github.com/cosmos/cosmos-sdk/pull/14847) App and ModuleManager methods `InitGenesis`, `ExportGenesis`, `BeginBlock` and `EndBlock` now also return an error. * (simulation) [#14728](https://github.com/cosmos/cosmos-sdk/pull/14728) Rename the `ParamChanges` field to `LegacyParamChange` and `Contents` to `LegacyProposalContents` in `simulation.SimulationState`. Additionally it adds a `ProposalMsgs` field to `simulation.SimulationState`. diff --git a/crypto/keys/secp256k1/secp256k1_test.go b/crypto/keys/secp256k1/secp256k1_test.go index 4c4ce4ceee7c..b601edeba27e 100644 --- a/crypto/keys/secp256k1/secp256k1_test.go +++ b/crypto/keys/secp256k1/secp256k1_test.go @@ -95,7 +95,7 @@ Here are the specific versions used to generate the vectors. github.com/cosmos/btcutil v1.0.5 github.com/cosmos/cosmos-sdk v0.46.8 */ -func generateKeyForCheckingConsistency() keyData { +var _ = func() keyData { priv := secp256k1.GenPrivKey() encPriv := make([]byte, len(priv.Key)*2) hex.Encode(encPriv, priv.Key) diff --git a/simapp/app_v2.go b/simapp/app_v2.go index b92c6e5208c0..f59c93db37f3 100644 --- a/simapp/app_v2.go +++ b/simapp/app_v2.go @@ -202,7 +202,7 @@ func NewSimApp( // For providing a custom a base account type add it below. // By default the auth module uses authtypes.ProtoBaseAccount(). // - // func() authtypes.AccountI { return authtypes.ProtoBaseAccount() }, + // func() sdk.AccountI { return authtypes.ProtoBaseAccount() }, // // MINT diff --git a/simapp/params/params.go b/simapp/params/params.go deleted file mode 100644 index b6aa5fb55e0f..000000000000 --- a/simapp/params/params.go +++ /dev/null @@ -1,7 +0,0 @@ -package params - -// Simulation parameter constants -const ( - StakePerAccount = "stake_per_account" - InitiallyBondedValidators = "initially_bonded_validators" -) diff --git a/simapp/sim_bench_test.go b/simapp/sim_bench_test.go index 0d88c63afe02..cb38d99935dc 100644 --- a/simapp/sim_bench_test.go +++ b/simapp/sim_bench_test.go @@ -49,7 +49,7 @@ func BenchmarkFullAppSimulation(b *testing.B) { b, os.Stdout, app.BaseApp, - AppStateFn(app.AppCodec(), app.SimulationManager()), + simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()), simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 simtestutil.SimulationOperations(app, app.AppCodec(), config), BlockedAddresses(), @@ -104,7 +104,7 @@ func BenchmarkInvariants(b *testing.B) { b, os.Stdout, app.BaseApp, - AppStateFn(app.AppCodec(), app.SimulationManager()), + simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()), simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 simtestutil.SimulationOperations(app, app.AppCodec(), config), BlockedAddresses(), diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 57a37c11d88f..e104e62a513a 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -91,7 +91,7 @@ func TestFullAppSimulation(t *testing.T) { t, os.Stdout, app.BaseApp, - AppStateFn(app.AppCodec(), app.SimulationManager()), + simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()), simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 simtestutil.SimulationOperations(app, app.AppCodec(), config), BlockedAddresses(), @@ -136,7 +136,7 @@ func TestAppImportExport(t *testing.T) { t, os.Stdout, app.BaseApp, - AppStateFn(app.AppCodec(), app.SimulationManager()), + simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()), simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 simtestutil.SimulationOperations(app, app.AppCodec(), config), BlockedAddresses(), @@ -253,7 +253,7 @@ func TestAppSimulationAfterImport(t *testing.T) { t, os.Stdout, app.BaseApp, - AppStateFn(app.AppCodec(), app.SimulationManager()), + simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()), simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 simtestutil.SimulationOperations(app, app.AppCodec(), config), BlockedAddresses(), @@ -301,7 +301,7 @@ func TestAppSimulationAfterImport(t *testing.T) { t, os.Stdout, newApp.BaseApp, - AppStateFn(app.AppCodec(), app.SimulationManager()), + simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()), simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 simtestutil.SimulationOperations(newApp, newApp.AppCodec(), config), BlockedAddresses(), @@ -356,7 +356,7 @@ func TestAppStateDeterminism(t *testing.T) { t, os.Stdout, app.BaseApp, - AppStateFn(app.AppCodec(), app.SimulationManager()), + simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()), simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 simtestutil.SimulationOperations(app, app.AppCodec(), config), BlockedAddresses(), diff --git a/simapp/state.go b/testutil/sims/state_helpers.go similarity index 80% rename from simapp/state.go rename to testutil/sims/state_helpers.go index ef3af1cee1d4..52e324065061 100644 --- a/simapp/state.go +++ b/testutil/sims/state_helpers.go @@ -1,4 +1,4 @@ -package simapp +package sims import ( "encoding/json" @@ -8,12 +8,10 @@ import ( "os" "time" + "cosmossdk.io/math" cmtjson "github.com/cometbft/cometbft/libs/json" cmttypes "github.com/cometbft/cometbft/types" - "cosmossdk.io/math" - simappparams "cosmossdk.io/simapp/params" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" @@ -25,11 +23,21 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) +// Simulation parameter constants +const ( + StakePerAccount = "stake_per_account" + InitiallyBondedValidators = "initially_bonded_validators" +) + // AppStateFn returns the initial application state using a genesis or the simulation parameters. // It panics if the user provides files for both of them. // If a file is not given for the genesis or the sim params, it creates a randomized one. -func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simtypes.AppStateFn { - return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config, +// genesisState is the default genesis state of the whole app. +func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager, genesisState map[string]json.RawMessage) simtypes.AppStateFn { + return func( + r *rand.Rand, + accs []simtypes.Account, + config simtypes.Config, ) (appState json.RawMessage, simAccs []simtypes.Account, chainID string, genesisTimestamp time.Time) { if simcli.FlagGenesisTimeValue == 0 { genesisTimestamp = simtypes.RandTimestamp(r) @@ -44,7 +52,10 @@ func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simty case config.GenesisFile != "": // override the default chain-id from simapp to set it later to the config - genesisDoc, accounts := AppStateFromGenesisFileFn(r, cdc, config.GenesisFile) + genesisDoc, accounts, err := AppStateFromGenesisFileFn(r, cdc, config.GenesisFile) + if err != nil { + panic(err) + } if simcli.FlagGenesisTimeValue == 0 { // use genesis timestamp if no custom timestamp is provided (i.e no random timestamp) @@ -66,11 +77,11 @@ func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simty if err != nil { panic(err) } - appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams) + appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams, genesisState) default: appParams := make(simtypes.AppParams) - appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams) + appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams, genesisState) } rawState := make(map[string]json.RawMessage) @@ -85,8 +96,7 @@ func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simty } stakingState := new(stakingtypes.GenesisState) - err = cdc.UnmarshalJSON(stakingStateBz, stakingState) - if err != nil { + if err = cdc.UnmarshalJSON(stakingStateBz, stakingState); err != nil { panic(err) } // compute not bonded balance @@ -105,8 +115,7 @@ func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simty panic("bank genesis state is missing") } bankState := new(banktypes.GenesisState) - err = cdc.UnmarshalJSON(bankStateBz, bankState) - if err != nil { + if err = cdc.UnmarshalJSON(bankStateBz, bankState); err != nil { panic(err) } @@ -141,12 +150,15 @@ func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simty // AppStateRandomizedFn creates calls each module's GenesisState generator function // and creates the simulation params func AppStateRandomizedFn( - simManager *module.SimulationManager, r *rand.Rand, cdc codec.JSONCodec, - accs []simtypes.Account, genesisTimestamp time.Time, appParams simtypes.AppParams, + simManager *module.SimulationManager, + r *rand.Rand, + cdc codec.JSONCodec, + accs []simtypes.Account, + genesisTimestamp time.Time, + appParams simtypes.AppParams, + genesisState map[string]json.RawMessage, ) (json.RawMessage, []simtypes.Account) { numAccs := int64(len(accs)) - genesisState := ModuleBasics.DefaultGenesis(cdc) - // generate a random amount of initial stake coins and a random initial // number of bonded accounts var ( @@ -154,11 +166,11 @@ func AppStateRandomizedFn( initialStake math.Int ) appParams.GetOrGenerate( - cdc, simappparams.StakePerAccount, &initialStake, r, + cdc, StakePerAccount, &initialStake, r, func(r *rand.Rand) { initialStake = math.NewInt(r.Int63n(1e12)) }, ) appParams.GetOrGenerate( - cdc, simappparams.InitiallyBondedValidators, &numInitiallyBonded, r, + cdc, InitiallyBondedValidators, &numInitiallyBonded, r, func(r *rand.Rand) { numInitiallyBonded = int64(r.Intn(300)) }, ) @@ -199,7 +211,7 @@ func AppStateRandomizedFn( // AppStateFromGenesisFileFn util function to generate the genesis AppState // from a genesis.json file. -func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile string) (cmttypes.GenesisDoc, []simtypes.Account) { +func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile string) (cmttypes.GenesisDoc, []simtypes.Account, error) { bytes, err := os.ReadFile(genesisFile) if err != nil { panic(err) @@ -207,15 +219,13 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile str var genesis cmttypes.GenesisDoc // NOTE: CometBFT uses a custom JSON decoder for GenesisDoc - err = cmtjson.Unmarshal(bytes, &genesis) - if err != nil { - panic(err) + if err = cmtjson.Unmarshal(bytes, &genesis); err != nil { + return genesis, nil, err } - var appState GenesisState - err = json.Unmarshal(genesis.AppState, &appState) - if err != nil { - panic(err) + var appState map[string]json.RawMessage + if err = json.Unmarshal(genesis.AppState, &appState); err != nil { + return genesis, nil, err } var authGenesis authtypes.GenesisState @@ -235,9 +245,9 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile str privKey := secp256k1.GenPrivKeyFromSecret(privkeySeed) - a, ok := acc.GetCachedValue().(authtypes.AccountI) + a, ok := acc.GetCachedValue().(sdk.AccountI) if !ok { - panic("expected account") + return genesis, nil, fmt.Errorf("expected account") } // create simulator accounts @@ -245,5 +255,5 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile str newAccs[i] = simAcc } - return genesis, newAccs + return genesis, newAccs, nil }