From c3299ef81cf46c17d03d404805f3c8454148607d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 30 Sep 2024 15:00:16 +0530 Subject: [PATCH 01/59] debug sim test --- app/app.go | 9 +- app/encoding.go | 1 - app/modules.go | 119 ++++++++++++++++++ app/sim/sim_config.go | 75 +++++++++++ app/sim/sim_state.go | 283 ++++++++++++++++++++++++++++++++++++++++++ app/sim/sim_utils.go | 76 ++++++++++++ app/sim_test.go | 209 +++++++++++++++++++++++++++++++ sims.mk | 70 +++++++++++ 8 files changed, 840 insertions(+), 2 deletions(-) create mode 100644 app/modules.go create mode 100644 app/sim/sim_config.go create mode 100644 app/sim/sim_state.go create mode 100644 app/sim/sim_utils.go create mode 100644 app/sim_test.go create mode 100644 sims.mk diff --git a/app/app.go b/app/app.go index cc271fc35f..3f8c295b31 100644 --- a/app/app.go +++ b/app/app.go @@ -259,6 +259,7 @@ type App struct { mm *module.Manager sm *module.SimulationManager + ModuleBasics module.BasicManager configurator module.Configurator // sdk keepers @@ -737,6 +738,8 @@ func New( authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), ) + app.ModuleBasics = newBasicManagerFromManager(app) + // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. @@ -812,6 +815,10 @@ func New( app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) app.mm.RegisterServices(app.configurator) + app.sm = module.NewSimulationManager(simulationModules(app, appCodec, skipGenesisInvariants)...) + + app.sm.RegisterStoreDecoders() + // initialize stores app.MountKVStores(keys) app.MountTransientStores(tKeys) @@ -962,7 +969,7 @@ func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // Register legacy and grpc-gateway routes for all modules. - ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + app.ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // register app's OpenAPI routes. if apiConfig.Swagger { diff --git a/app/encoding.go b/app/encoding.go index 2e8c728b0f..dbf32a0878 100644 --- a/app/encoding.go +++ b/app/encoding.go @@ -14,7 +14,6 @@ import ( evmenc "github.com/zeta-chain/ethermint/encoding" ethermint "github.com/zeta-chain/ethermint/types" evmtypes "github.com/zeta-chain/ethermint/x/evm/types" - authoritytypes "github.com/zeta-chain/node/x/authority/types" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" emissionstypes "github.com/zeta-chain/node/x/emissions/types" diff --git a/app/modules.go b/app/modules.go new file mode 100644 index 0000000000..34e2660a6a --- /dev/null +++ b/app/modules.go @@ -0,0 +1,119 @@ +package app + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/auth" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" + "github.com/cosmos/cosmos-sdk/x/bank" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distr "github.com/cosmos/cosmos-sdk/x/distribution" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/evidence" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/cosmos/cosmos-sdk/x/gov" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/slashing" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// ModuleBasics defines the module BasicManager that is in charge of setting up basic, +// non-dependant module elements, such as codec registration +// and genesis verification. +func newBasicManagerFromManager(app *App) module.BasicManager { + var moduleBasics []module.AppModuleBasic + for _, m := range app.mm.Modules { + m, ok := m.(module.AppModuleBasic) + if !ok { + fmt.Printf("module %s is not an instance of module.AppModuleBasic\n", m) + continue + } + if m.Name() == govtypes.ModuleName { + m = gov.NewAppModuleBasic(getGovProposalHandlers()) + } + + if m.Name() == genutiltypes.ModuleName { + m = genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator) + } + + moduleBasics = append(moduleBasics, m) + } + basicManager := module.NewBasicManager(moduleBasics...) + //basicManager.RegisterLegacyAminoCodec(app.cdc) + basicManager.RegisterInterfaces(app.interfaceRegistry) + + return basicManager +} + +func simulationModules( + app *App, + appCodec codec.Codec, + _ bool, +) []module.AppModuleSimulation { + return []module.AppModuleSimulation{ + auth.NewAppModule(appCodec, app.AccountKeeper, RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), + gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), + staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), + distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), + slashing.NewAppModule( + appCodec, + app.SlashingKeeper, + app.AccountKeeper, + app.BankKeeper, + app.StakingKeeper, + app.GetSubspace(slashingtypes.ModuleName), + ), + params.NewAppModule(app.ParamsKeeper), + evidence.NewAppModule(app.EvidenceKeeper), + authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), + } +} + +// RandomGenesisAccounts defines the default RandomGenesisAccountsFn used on the SDK. +// It creates a slice of BaseAccount, ContinuousVestingAccount and DelayedVestingAccount. +func RandomGenesisAccounts(simState *module.SimulationState) authtypes.GenesisAccounts { + genesisAccs := make(authtypes.GenesisAccounts, len(simState.Accounts)) + for i, acc := range simState.Accounts { + bacc := authtypes.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.Int64()))) + 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 +} diff --git a/app/sim/sim_config.go b/app/sim/sim_config.go new file mode 100644 index 0000000000..43c150303e --- /dev/null +++ b/app/sim/sim_config.go @@ -0,0 +1,75 @@ +package sim + +import ( + "flag" + + "github.com/cosmos/cosmos-sdk/types/simulation" +) + +// List of available flags for the simulator +var ( + FlagGenesisFileValue string + FlagParamsFileValue string + FlagExportParamsPathValue string + FlagExportParamsHeightValue int + FlagExportStatePathValue string + FlagExportStatsPathValue string + FlagSeedValue int64 + FlagInitialBlockHeightValue int + FlagNumBlocksValue int + FlagBlockSizeValue int + FlagLeanValue bool + FlagCommitValue bool + FlagOnOperationValue bool // TODO: Remove in favor of binary search for invariant violation + FlagAllInvariantsValue bool + + FlagEnabledValue bool + FlagVerboseValue bool + FlagPeriodValue uint + FlagGenesisTimeValue int64 +) + +// GetSimulatorFlags gets the values of all the available simulation flags +func GetSimulatorFlags() { + // config fields + flag.StringVar(&FlagGenesisFileValue, "Genesis", "", "custom simulation genesis file; cannot be used with params file") + flag.StringVar(&FlagParamsFileValue, "Params", "", "custom simulation params file which overrides any random params; cannot be used with genesis") + flag.StringVar(&FlagExportParamsPathValue, "ExportParamsPath", "", "custom file path to save the exported params JSON") + flag.IntVar(&FlagExportParamsHeightValue, "ExportParamsHeight", 0, "height to which export the randomly generated params") + flag.StringVar(&FlagExportStatePathValue, "ExportStatePath", "", "custom file path to save the exported app state JSON") + flag.StringVar(&FlagExportStatsPathValue, "ExportStatsPath", "", "custom file path to save the exported simulation statistics JSON") + flag.Int64Var(&FlagSeedValue, "Seed", 42, "simulation random seed") + flag.IntVar(&FlagInitialBlockHeightValue, "InitialBlockHeight", 1, "initial block to start the simulation") + flag.IntVar(&FlagNumBlocksValue, "NumBlocks", 500, "number of new blocks to simulate from the initial block height") + flag.IntVar(&FlagBlockSizeValue, "BlockSize", 200, "operations per block") + flag.BoolVar(&FlagLeanValue, "Lean", false, "lean simulation log output") + flag.BoolVar(&FlagCommitValue, "Commit", false, "have the simulation commit") + flag.BoolVar(&FlagOnOperationValue, "SimulateEveryOperation", false, "run slow invariants every operation") + flag.BoolVar(&FlagAllInvariantsValue, "PrintAllInvariants", false, "print all invariants if a broken invariant is found") + + // simulation flags + flag.BoolVar(&FlagEnabledValue, "Enabled", false, "enable the simulation") + flag.BoolVar(&FlagVerboseValue, "Verbose", false, "verbose log output") + flag.UintVar(&FlagPeriodValue, "Period", 0, "run slow invariants only once every period assertions") + flag.Int64Var(&FlagGenesisTimeValue, "GenesisTime", 0, "override genesis UNIX time instead of using a random UNIX time") +} + +// NewConfigFromFlags creates a simulation from the retrieved values of the flags. +func NewConfigFromFlags() simulation.Config { + return simulation.Config{ + GenesisFile: FlagGenesisFileValue, + ParamsFile: FlagParamsFileValue, + ExportParamsPath: FlagExportParamsPathValue, + ExportParamsHeight: FlagExportParamsHeightValue, + ExportStatePath: FlagExportStatePathValue, + ExportStatsPath: FlagExportStatsPathValue, + Seed: FlagSeedValue, + InitialBlockHeight: FlagInitialBlockHeightValue, + NumBlocks: FlagNumBlocksValue, + BlockSize: FlagBlockSizeValue, + Lean: FlagLeanValue, + Commit: FlagCommitValue, + OnOperation: FlagOnOperationValue, + AllInvariants: FlagAllInvariantsValue, + } +} diff --git a/app/sim/sim_state.go b/app/sim/sim_state.go new file mode 100644 index 0000000000..ad305d4720 --- /dev/null +++ b/app/sim/sim_state.go @@ -0,0 +1,283 @@ +package sim + +import ( + "encoding/json" + "fmt" + "io" + "math/rand" + "os" + "time" + + "cosmossdk.io/math" + cmtjson "github.com/cometbft/cometbft/libs/json" + tmtypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + 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" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + zetaapp "github.com/zeta-chain/node/app" +) + +// 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.Codec, 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 FlagGenesisTimeValue == 0 { + genesisTimestamp = simtypes.RandTimestamp(r) + } else { + genesisTimestamp = time.Unix(FlagGenesisTimeValue, 0) + } + + chainID = config.ChainID + switch { + case config.ParamsFile != "" && config.GenesisFile != "": + panic("cannot provide both a genesis file and a params file") + + case config.GenesisFile != "": + // override the default chain-id from simapp to set it later to the config + genesisDoc, accounts, err := AppStateFromGenesisFileFn(r, cdc, config.GenesisFile) + if err != nil { + panic(err) + } + + if FlagGenesisTimeValue == 0 { + // use genesis timestamp if no custom timestamp is provided (i.e no random timestamp) + genesisTimestamp = genesisDoc.GenesisTime + } + + appState = genesisDoc.AppState + chainID = genesisDoc.ChainID + simAccs = accounts + + case config.ParamsFile != "": + appParams := make(simtypes.AppParams) + bz, err := os.ReadFile(config.ParamsFile) + if err != nil { + panic(err) + } + + err = json.Unmarshal(bz, &appParams) + if err != nil { + panic(err) + } + appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams, genesisState) + + default: + appParams := make(simtypes.AppParams) + + genutilGenesis, ok := genesisState[genutiltypes.ModuleName] + if !ok { + panic("genutil genesis state is missing") + } + genutilState := new(genutiltypes.GenesisState) + err := cdc.UnmarshalJSON(genutilGenesis, genutilState) + if err != nil { + panic(err) + } + fmt.Println("Genesis transactions:", len(genutilState.GenTxs)) + appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams, genesisState) + } + + rawState := make(map[string]json.RawMessage) + err := json.Unmarshal(appState, &rawState) + if err != nil { + panic(err) + } + + //genutilGenesis, ok := rawState[genutiltypes.ModuleName] + //if !ok { + // panic("genutil genesis state is missing") + //} + //genutilState := new(genutiltypes.GenesisState) + //err = cdc.UnmarshalJSON(genutilGenesis, genutilState) + //if err != nil { + // panic(err) + //} + // + //fmt.Println("Genesis transactions:", len(genutilState.GenTxs)) + // + //for _, acc := range genutilState.GenTxs { + // fmt.Println(acc) + //} + + stakingStateBz, ok := rawState[stakingtypes.ModuleName] + if !ok { + panic("staking genesis state is missing") + } + + stakingState := new(stakingtypes.GenesisState) + err = cdc.UnmarshalJSON(stakingStateBz, stakingState) + if err != nil { + panic(err) + } + // compute not bonded balance + notBondedTokens := math.ZeroInt() + for _, val := range stakingState.Validators { + if val.Status != stakingtypes.Unbonded { + continue + } + notBondedTokens = notBondedTokens.Add(val.GetTokens()) + } + notBondedCoins := sdk.NewCoin(stakingState.Params.BondDenom, notBondedTokens) + // edit bank state to make it have the not bonded pool tokens + bankStateBz, ok := rawState[banktypes.ModuleName] + // TODO(fdymylja/jonathan): should we panic in this case + if !ok { + panic("bank genesis state is missing") + } + bankState := new(banktypes.GenesisState) + err = cdc.UnmarshalJSON(bankStateBz, bankState) + if err != nil { + panic(err) + } + + stakingAddr := authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName).String() + var found bool + for _, balance := range bankState.Balances { + if balance.Address == stakingAddr { + found = true + break + } + } + if !found { + bankState.Balances = append(bankState.Balances, banktypes.Balance{ + Address: stakingAddr, + Coins: sdk.NewCoins(notBondedCoins), + }) + } + + // change appState back + rawState[stakingtypes.ModuleName] = cdc.MustMarshalJSON(stakingState) + rawState[banktypes.ModuleName] = cdc.MustMarshalJSON(bankState) + + // replace appstate + appState, err = json.Marshal(rawState) + if err != nil { + panic(err) + } + return appState, simAccs, chainID, genesisTimestamp + } +} + +// AppStateRandomizedFn creates calls each module's GenesisState generator function +// and creates the simulation params +func AppStateRandomizedFn( + simManager *module.SimulationManager, r *rand.Rand, cdc codec.Codec, + accs []simtypes.Account, genesisTimestamp time.Time, appParams simtypes.AppParams, + genesisState map[string]json.RawMessage, +) (json.RawMessage, []simtypes.Account) { + numAccs := int64(len(accs)) + // generate a random amount of initial stake coins and a random initial + // number of bonded accounts + var ( + numInitiallyBonded int64 + initialStake math.Int + ) + + appParams.GetOrGenerate(cdc, + StakePerAccount, &initialStake, r, + func(r *rand.Rand) { initialStake = math.NewInt(r.Int63n(1e12)) }, + ) + appParams.GetOrGenerate(cdc, + InitiallyBondedValidators, &numInitiallyBonded, r, + func(r *rand.Rand) { numInitiallyBonded = int64(r.Intn(300)) }, + ) + + if numInitiallyBonded > numAccs { + numInitiallyBonded = numAccs + } + + fmt.Printf( + `Selected randomly generated parameters for simulated genesis: +{ + stake_per_account: "%d", + initially_bonded_validators: "%d" +} +`, initialStake, numInitiallyBonded, + ) + + simState := &module.SimulationState{ + AppParams: appParams, + Cdc: cdc, + Rand: r, + GenState: genesisState, + Accounts: accs, + InitialStake: initialStake, + NumBonded: numInitiallyBonded, + GenTimestamp: genesisTimestamp, + } + + simManager.GenerateGenesisStates(simState) + + appState, err := json.Marshal(genesisState) + if err != nil { + panic(err) + } + + return appState, accs +} + +// AppStateFromGenesisFileFn util function to generate the genesis AppState +// from a genesis.json file. +func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile string) (tmtypes.GenesisDoc, []simtypes.Account, error) { + bytes, err := os.ReadFile(genesisFile) + if err != nil { + panic(err) + } + + var genesis tmtypes.GenesisDoc + // NOTE: Comet uses a custom JSON decoder for GenesisDoc + err = cmtjson.Unmarshal(bytes, &genesis) + if err != nil { + panic(err) + } + + var appState zetaapp.GenesisState + err = json.Unmarshal(genesis.AppState, &appState) + if err != nil { + panic(err) + } + + var authGenesis authtypes.GenesisState + if appState[authtypes.ModuleName] != nil { + cdc.MustUnmarshalJSON(appState[authtypes.ModuleName], &authGenesis) + } + + newAccs := make([]simtypes.Account, len(authGenesis.Accounts)) + for i, acc := range authGenesis.Accounts { + // Pick a random private key, since we don't know the actual key + // This should be fine as it's only used for mock Tendermint validators + // and these keys are never actually used to sign by mock Tendermint. + privkeySeed := make([]byte, 15) + if _, err := r.Read(privkeySeed); err != nil { + panic(err) + } + + privKey := secp256k1.GenPrivKeyFromSecret(privkeySeed) + + a, ok := acc.GetCachedValue().(authtypes.AccountI) + if !ok { + return genesis, nil, fmt.Errorf("expected account") + } + + // create simulator accounts + simAcc := simtypes.Account{PrivKey: privKey, PubKey: privKey.PubKey(), Address: a.GetAddress()} + newAccs[i] = simAcc + } + + return genesis, newAccs, nil +} diff --git a/app/sim/sim_utils.go b/app/sim/sim_utils.go new file mode 100644 index 0000000000..da915257f9 --- /dev/null +++ b/app/sim/sim_utils.go @@ -0,0 +1,76 @@ +package sim + +import ( + "encoding/json" + "fmt" + "os" + + dbm "github.com/cometbft/cometbft-db" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + zetaapp "github.com/zeta-chain/node/app" +) + +// SimulationOperations retrieves the simulation params from the provided file path +// and returns all the modules weighted operations +func SimulationOperations(app *zetaapp.App, cdc codec.JSONCodec, config simtypes.Config) []simtypes.WeightedOperation { + simState := module.SimulationState{ + AppParams: make(simtypes.AppParams), + Cdc: cdc, + } + + if config.ParamsFile != "" { + bz, err := os.ReadFile(config.ParamsFile) + if err != nil { + panic(err) + } + + err = json.Unmarshal(bz, &simState.AppParams) + if err != nil { + panic(err) + } + } + + simState.LegacyProposalContents = app.SimulationManager().GetProposalContents(simState) //nolint:staticcheck + simState.ProposalMsgs = app.SimulationManager().GetProposalMsgs(simState) + return app.SimulationManager().WeightedOperations(simState) +} + +// CheckExportSimulation exports the app state and simulation parameters to JSON +// if the export paths are defined. +func CheckExportSimulation(app runtime.AppI, config simtypes.Config, params simtypes.Params) error { + if config.ExportStatePath != "" { + fmt.Println("exporting app state...") + exported, err := app.ExportAppStateAndValidators(false, nil, nil) + if err != nil { + return err + } + + if err := os.WriteFile(config.ExportStatePath, []byte(exported.AppState), 0o600); err != nil { + return err + } + } + + if config.ExportParamsPath != "" { + fmt.Println("exporting simulation params...") + paramsBz, err := json.MarshalIndent(params, "", " ") + if err != nil { + return err + } + + if err := os.WriteFile(config.ExportParamsPath, paramsBz, 0o600); err != nil { + return err + } + } + return nil +} + +// PrintStats prints the corresponding statistics from the app DB. +func PrintStats(db dbm.DB) { + fmt.Println("\nLevelDB Stats") + fmt.Println(db.Stats()["leveldb.stats"]) + fmt.Println("LevelDB cached block size", db.Stats()["leveldb.cachedblock"]) +} diff --git a/app/sim_test.go b/app/sim_test.go new file mode 100644 index 0000000000..76fba034d8 --- /dev/null +++ b/app/sim_test.go @@ -0,0 +1,209 @@ +package app_test + +import ( + "encoding/json" + "fmt" + "math/rand" + "os" + "testing" + + "github.com/cometbft/cometbft/libs/log" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/ethermint/app" + evmante "github.com/zeta-chain/ethermint/app/ante" + evmtypes "github.com/zeta-chain/ethermint/x/evm/types" + zetaapp "github.com/zeta-chain/node/app" + "github.com/zeta-chain/node/app/ante" + + dbm "github.com/cometbft/cometbft-db" + + "github.com/cosmos/cosmos-sdk/store" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/server" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + simulation2 "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli" + + // "github.com/cosmos/gaia/v11/app/helpers" + // "github.com/cosmos/gaia/v11/app/params" + "github.com/zeta-chain/node/app/sim" +) + +// AppChainID hardcoded chainID for simulation + +func init() { + sim.GetSimulatorFlags() +} + +const ( + SimAppChainID = "simulation_777-1" + SimBlockMaxGas = 815000000 + TestAppChainID = "zetachain_777-1" +) + +// NewSimApp disable feemarket on native tx, otherwise the cosmos-sdk simulation tests will fail. +func NewSimApp(logger log.Logger, db dbm.DB, appOptions servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp)) (*zetaapp.App, error) { + + encCdc := zetaapp.MakeEncodingConfig() + app := zetaapp.New( + logger, + db, + nil, + false, + map[int64]bool{}, + app.DefaultNodeHome, + 5, + encCdc, + appOptions, + baseAppOptions..., + ) + // disable feemarket on native tx + options := ante.HandlerOptions{ + AccountKeeper: app.AccountKeeper, + BankKeeper: app.BankKeeper, + EvmKeeper: app.EvmKeeper, + FeeMarketKeeper: app.FeeMarketKeeper, + SignModeHandler: encCdc.TxConfig.SignModeHandler(), + SigGasConsumer: evmante.DefaultSigVerificationGasConsumer, + MaxTxGasWanted: 0, + ObserverKeeper: app.ObserverKeeper, + } + + anteHandler, err := ante.NewAnteHandler(options) + if err != nil { + panic(err) + } + + app.SetAnteHandler(anteHandler) + if err := app.LoadLatestVersion(); err != nil { + return nil, err + } + return app, nil +} + +// interBlockCacheOpt returns a BaseApp option function that sets the persistent +// inter-block write-through cache. +func interBlockCacheOpt() func(*baseapp.BaseApp) { + return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager()) +} + +// TODO: Make another test for the fuzzer itself, which just has noOp txs +// and doesn't depend on the application. +func TestAppStateDeterminism(t *testing.T) { + if !sim.FlagEnabledValue { + t.Skip("skipping application simulation") + } + + config := sim.NewConfigFromFlags() + config.InitialBlockHeight = 1 + config.ExportParamsPath = "" + config.OnOperation = false + config.AllInvariants = false + config.ChainID = SimAppChainID + + numSeeds := 3 + numTimesToRunPerSeed := 5 + + // We will be overriding the random seed and just run a single simulation on the provided seed value + if config.Seed != simcli.DefaultSeedValue { + numSeeds = 1 + } + + appHashList := make([]json.RawMessage, numTimesToRunPerSeed) + appOptions := make(simtestutil.AppOptionsMap, 0) + appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue + + for i := 0; i < numSeeds; i++ { + if config.Seed == simcli.DefaultSeedValue { + config.Seed = rand.Int63() + } + + fmt.Println("config.Seed: ", config.Seed) + + for j := 0; j < numTimesToRunPerSeed; j++ { + var logger log.Logger + if sim.FlagVerboseValue { + logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + } else { + logger = log.NewNopLogger() + } + + db := dbm.NewMemDB() + dir, err := os.MkdirTemp("", "zeta-simulation") + require.NoError(t, err) + appOptions[flags.FlagHome] = dir + + app, err := NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + + fmt.Printf( + "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n", + config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed, + ) + + blockedAddresses := app.ModuleAccountAddrs() + + _, _, err = simulation.SimulateFromSeed( + t, + os.Stdout, + app.BaseApp, + sim.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), + simulation2.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 + simtestutil.SimulationOperations(app, app.AppCodec(), config), + blockedAddresses, + config, + app.AppCodec(), + ) + require.NoError(t, err) + + if config.Commit { + sim.PrintStats(db) + } + + appHash := app.LastCommitID().Hash + appHashList[j] = appHash + + if j != 0 { + require.Equal( + t, string(appHashList[0]), string(appHashList[j]), + "non-determinism in seed %d: %d/%d, attempt: %d/%d\n", config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed, + ) + } + } + } +} + +func CFn(app *zetaapp.App) simulation2.AppStateFn { + var bondDenom string + return simtestutil.AppStateFnWithExtendedCbs( + app.AppCodec(), + app.SimulationManager(), + app.ModuleBasics.DefaultGenesis(app.AppCodec()), + func(moduleName string, genesisState interface{}) { + if moduleName == stakingtypes.ModuleName { + stakingState := genesisState.(*stakingtypes.GenesisState) + bondDenom = stakingState.Params.BondDenom + } + }, + func(rawState map[string]json.RawMessage) { + + evmStateBz, ok := rawState[evmtypes.ModuleName] + if !ok { + panic("evm genesis state is missing") + } + + evmState := new(evmtypes.GenesisState) + app.AppCodec().MustUnmarshalJSON(evmStateBz, evmState) + + // we should replace the EvmDenom with BondDenom + evmState.Params.EvmDenom = bondDenom + + // change appState back + rawState[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(evmState) + }, + ) +} diff --git a/sims.mk b/sims.mk new file mode 100644 index 0000000000..c17cd9560a --- /dev/null +++ b/sims.mk @@ -0,0 +1,70 @@ +#!/usr/bin/make -f + +######################################## +### Simulations + +BINDIR ?= $(GOPATH)/bin +SIMAPP = ./app +test-sim-nondeterminism: + @echo "Running non-determinism test..." + @go test -mod=readonly $(SIMAPP) -run TestAppStateDeterminism -Enabled=true \ + -NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h + +test-sim-custom-genesis-fast: + @echo "Running custom genesis simulation..." + @echo "By default, ${HOME}/.gaia/config/genesis.json will be used." + @go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation -Genesis=${HOME}/.gaia/config/genesis.json \ + -Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h + +test-sim-import-export: runsim + @echo "Running application import/export simulation. This may take several minutes..." + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppImportExport + +test-sim-after-import: runsim + @echo "Running application simulation-after-import. This may take several minutes..." + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppSimulationAfterImport + +test-sim-custom-genesis-multi-seed: runsim + @echo "Running multi-seed custom genesis simulation..." + @echo "By default, ${HOME}/.gaia/config/genesis.json will be used." + @$(BINDIR)/runsim -Genesis=${HOME}/.gaia/config/genesis.json -SimAppPkg=$(SIMAPP) -ExitOnFail 400 5 TestFullAppSimulation + +test-sim-multi-seed-long: runsim + @echo "Running long multi-seed application simulation. This may take awhile!" + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestFullAppSimulation + +test-sim-multi-seed-short: runsim + @echo "Running short multi-seed application simulation. This may take awhile!" + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation + +test-sim-benchmark-invariants: + @echo "Running simulation invariant benchmarks..." + @go test -mod=readonly $(SIMAPP) -benchmem -bench=BenchmarkInvariants -run=^$ \ + -Enabled=true -NumBlocks=1000 -BlockSize=200 \ + -Period=1 -Commit=true -Seed=57 -v -timeout 24h + +.PHONY: \ +test-sim-nondeterminism \ +test-sim-custom-genesis-fast \ +test-sim-import-export \ +test-sim-after-import \ +test-sim-custom-genesis-multi-seed \ +test-sim-multi-seed-short \ +test-sim-multi-seed-long \ +test-sim-benchmark-invariants + +SIM_NUM_BLOCKS ?= 500 +SIM_BLOCK_SIZE ?= 200 +SIM_COMMIT ?= true + +test-sim-benchmark: + @echo "Running application benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!" + @go test -mod=readonly -benchmem -run=^$$ $(SIMAPP) -bench ^BenchmarkFullAppSimulation$$ \ + -Enabled=true -NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -timeout 24h + +test-sim-profile: + @echo "Running application benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!" + @go test -mod=readonly -benchmem -run=^$$ $(SIMAPP) -bench ^BenchmarkFullAppSimulation$$ \ + -Enabled=true -NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out + +.PHONY: test-sim-profile test-sim-benchmark \ No newline at end of file From 7d9502118c40a1c2408438dcb98ac9aa5456cc96 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 1 Oct 2024 12:51:14 +0530 Subject: [PATCH 02/59] start modifuing for v50 --- app/sim/sim_state.go | 61 ++++++++++++++++++++++++-------------------- go.mod | 2 +- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/app/sim/sim_state.go b/app/sim/sim_state.go index ad305d4720..8d03fd8fbe 100644 --- a/app/sim/sim_state.go +++ b/app/sim/sim_state.go @@ -78,17 +78,6 @@ func AppStateFn(cdc codec.Codec, simManager *module.SimulationManager, genesisSt default: appParams := make(simtypes.AppParams) - - genutilGenesis, ok := genesisState[genutiltypes.ModuleName] - if !ok { - panic("genutil genesis state is missing") - } - genutilState := new(genutiltypes.GenesisState) - err := cdc.UnmarshalJSON(genutilGenesis, genutilState) - if err != nil { - panic(err) - } - fmt.Println("Genesis transactions:", len(genutilState.GenTxs)) appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams, genesisState) } @@ -98,22 +87,6 @@ func AppStateFn(cdc codec.Codec, simManager *module.SimulationManager, genesisSt panic(err) } - //genutilGenesis, ok := rawState[genutiltypes.ModuleName] - //if !ok { - // panic("genutil genesis state is missing") - //} - //genutilState := new(genutiltypes.GenesisState) - //err = cdc.UnmarshalJSON(genutilGenesis, genutilState) - //if err != nil { - // panic(err) - //} - // - //fmt.Println("Genesis transactions:", len(genutilState.GenTxs)) - // - //for _, acc := range genutilState.GenTxs { - // fmt.Println(acc) - //} - stakingStateBz, ok := rawState[stakingtypes.ModuleName] if !ok { panic("staking genesis state is missing") @@ -160,6 +133,38 @@ func AppStateFn(cdc codec.Codec, simManager *module.SimulationManager, genesisSt }) } + genustilStateBz, ok := rawState[genutiltypes.ModuleName] + if !ok { + panic("staking genesis state is missing") + } + + genutilState := new(genutiltypes.GenesisState) + err = cdc.UnmarshalJSON(genustilStateBz, genutilState) + if err != nil { + panic(err) + } + fmt.Println("------------------------------------------------") + fmt.Println("Genesis trasnactions :", len(genutilState.GenTxs)) + fmt.Println("Validators :", len(stakingState.Validators)) + max := 3 + for i, val := range stakingState.Validators { + if i == max { + break + } + fmt.Println("Validator :", val.OperatorAddress, val.Tokens, val.GetStatus()) + } + fmt.Println("Exported", stakingState.Exported) + fmt.Println("Bond Denom :", stakingState.Params.BondDenom) + fmt.Println("maxValidators", stakingState.Params.MaxValidators) + max = 3 + for i, val := range stakingState.LastValidatorPowers { + if i == max { + break + } + fmt.Println("LastValidatorPowers :", val.Address, val.Power) + } + fmt.Println("------------------------------------------------") + // change appState back rawState[stakingtypes.ModuleName] = cdc.MustMarshalJSON(stakingState) rawState[banktypes.ModuleName] = cdc.MustMarshalJSON(bankState) @@ -221,6 +226,8 @@ func AppStateRandomizedFn( GenTimestamp: genesisTimestamp, } + fmt.Println("Generating genesis states...") + simManager.GenerateGenesisStates(simState) appState, err := json.Marshal(genesisState) diff --git a/go.mod b/go.mod index 7625fc2047..17c8c18259 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/cometbft/cometbft v0.37.4 github.com/cometbft/cometbft-db v0.12.0 github.com/cosmos/btcutil v1.0.5 - github.com/cosmos/cosmos-sdk v0.47.10 + github.com/cosmos/cosmos-sdk v0.50.9 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.4.0 github.com/davecgh/go-spew v1.1.1 From fcce58ee0d8443ce54b2ee88c927bc18858cc37c Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 1 Oct 2024 19:15:55 +0530 Subject: [PATCH 03/59] add sim test v1 --- app/modules.go | 7 ++++++- app/sim/sim_state.go | 39 ++++++++++----------------------------- app/sim_test.go | 2 ++ go.mod | 2 +- sims.mk | 13 ++++++++++--- 5 files changed, 29 insertions(+), 34 deletions(-) diff --git a/app/modules.go b/app/modules.go index 34e2660a6a..37151b717c 100644 --- a/app/modules.go +++ b/app/modules.go @@ -20,11 +20,14 @@ import ( genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/cosmos/cosmos-sdk/x/gov" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + groupmodule "github.com/cosmos/cosmos-sdk/x/group/module" "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/slashing" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/zeta-chain/ethermint/x/evm" + evmtypes "github.com/zeta-chain/ethermint/x/evm/types" ) // ModuleBasics defines the module BasicManager that is in charge of setting up basic, @@ -63,7 +66,7 @@ func simulationModules( return []module.AppModuleSimulation{ auth.NewAppModule(appCodec, app.AccountKeeper, RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), - gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), + //gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), slashing.NewAppModule( @@ -76,7 +79,9 @@ func simulationModules( ), params.NewAppModule(app.ParamsKeeper), evidence.NewAppModule(app.EvidenceKeeper), + evm.NewAppModule(app.EvmKeeper, app.AccountKeeper, app.GetSubspace(evmtypes.ModuleName)), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), + groupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), } } diff --git a/app/sim/sim_state.go b/app/sim/sim_state.go index 8d03fd8fbe..12df57dc5c 100644 --- a/app/sim/sim_state.go +++ b/app/sim/sim_state.go @@ -18,8 +18,8 @@ import ( 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" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + evmtypes "github.com/zeta-chain/ethermint/x/evm/types" zetaapp "github.com/zeta-chain/node/app" ) @@ -97,6 +97,7 @@ func AppStateFn(cdc codec.Codec, simManager *module.SimulationManager, genesisSt if err != nil { panic(err) } + // compute not bonded balance notBondedTokens := math.ZeroInt() for _, val := range stakingState.Validators { @@ -133,39 +134,19 @@ func AppStateFn(cdc codec.Codec, simManager *module.SimulationManager, genesisSt }) } - genustilStateBz, ok := rawState[genutiltypes.ModuleName] + evmStateBz, ok := rawState[evmtypes.ModuleName] if !ok { - panic("staking genesis state is missing") + panic("evm genesis state is missing") } - genutilState := new(genutiltypes.GenesisState) - err = cdc.UnmarshalJSON(genustilStateBz, genutilState) - if err != nil { - panic(err) - } - fmt.Println("------------------------------------------------") - fmt.Println("Genesis trasnactions :", len(genutilState.GenTxs)) - fmt.Println("Validators :", len(stakingState.Validators)) - max := 3 - for i, val := range stakingState.Validators { - if i == max { - break - } - fmt.Println("Validator :", val.OperatorAddress, val.Tokens, val.GetStatus()) - } - fmt.Println("Exported", stakingState.Exported) - fmt.Println("Bond Denom :", stakingState.Params.BondDenom) - fmt.Println("maxValidators", stakingState.Params.MaxValidators) - max = 3 - for i, val := range stakingState.LastValidatorPowers { - if i == max { - break - } - fmt.Println("LastValidatorPowers :", val.Address, val.Power) - } - fmt.Println("------------------------------------------------") + evmState := new(evmtypes.GenesisState) + cdc.MustUnmarshalJSON(evmStateBz, evmState) + + // we should replace the EvmDenom with BondDenom + evmState.Params.EvmDenom = stakingState.Params.BondDenom // change appState back + rawState[evmtypes.ModuleName] = cdc.MustMarshalJSON(evmState) rawState[stakingtypes.ModuleName] = cdc.MustMarshalJSON(stakingState) rawState[banktypes.ModuleName] = cdc.MustMarshalJSON(bankState) diff --git a/app/sim_test.go b/app/sim_test.go index 76fba034d8..78fc003ccb 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -9,6 +9,7 @@ import ( "github.com/cometbft/cometbft/libs/log" servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/require" "github.com/zeta-chain/ethermint/app" @@ -62,6 +63,7 @@ func NewSimApp(logger log.Logger, db dbm.DB, appOptions servertypes.AppOptions, appOptions, baseAppOptions..., ) + sdk.DefaultPowerReduction = sdk.OneInt() // disable feemarket on native tx options := ante.HandlerOptions{ AccountKeeper: app.AccountKeeper, diff --git a/go.mod b/go.mod index 17c8c18259..7625fc2047 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/cometbft/cometbft v0.37.4 github.com/cometbft/cometbft-db v0.12.0 github.com/cosmos/btcutil v1.0.5 - github.com/cosmos/cosmos-sdk v0.50.9 + github.com/cosmos/cosmos-sdk v0.47.10 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.4.0 github.com/davecgh/go-spew v1.1.1 diff --git a/sims.mk b/sims.mk index c17cd9560a..e48b22cf81 100644 --- a/sims.mk +++ b/sims.mk @@ -5,14 +5,21 @@ BINDIR ?= $(GOPATH)/bin SIMAPP = ./app + +runsim: $(BINDIR)/runsim +$(BINDIR)/runsim: + @echo "Installing runsim..." + @(cd /tmp && go install github.com/cosmos/tools/cmd/runsim@v1.0.0) + + test-sim-nondeterminism: @echo "Running non-determinism test..." @go test -mod=readonly $(SIMAPP) -run TestAppStateDeterminism -Enabled=true \ - -NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h + -NumBlocks=10 -BlockSize=20 -Commit=true -Period=0 -v -timeout 24h test-sim-custom-genesis-fast: @echo "Running custom genesis simulation..." - @echo "By default, ${HOME}/.gaia/config/genesis.json will be used." + @echo "By default, ${HOME}/.zetacored/config/genesis.json will be used." @go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation -Genesis=${HOME}/.gaia/config/genesis.json \ -Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h @@ -26,7 +33,7 @@ test-sim-after-import: runsim test-sim-custom-genesis-multi-seed: runsim @echo "Running multi-seed custom genesis simulation..." - @echo "By default, ${HOME}/.gaia/config/genesis.json will be used." + @echo "By default, ${HOME}/.zetacored/config/genesis.json will be used." @$(BINDIR)/runsim -Genesis=${HOME}/.gaia/config/genesis.json -SimAppPkg=$(SIMAPP) -ExitOnFail 400 5 TestFullAppSimulation test-sim-multi-seed-long: runsim From b774b1e4f56ebea79c741a0b0a6b79265da10780 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 1 Oct 2024 20:04:16 +0530 Subject: [PATCH 04/59] add sim export --- app/sim_test.go | 67 +++++++++++++++++++++++++++++-------------------- sims.mk | 51 ++++++------------------------------- 2 files changed, 47 insertions(+), 71 deletions(-) diff --git a/app/sim_test.go b/app/sim_test.go index 78fc003ccb..c13538f451 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -10,11 +10,9 @@ import ( "github.com/cometbft/cometbft/libs/log" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/require" "github.com/zeta-chain/ethermint/app" evmante "github.com/zeta-chain/ethermint/app/ante" - evmtypes "github.com/zeta-chain/ethermint/x/evm/types" zetaapp "github.com/zeta-chain/node/app" "github.com/zeta-chain/node/app/ante" @@ -179,33 +177,48 @@ func TestAppStateDeterminism(t *testing.T) { } } -func CFn(app *zetaapp.App) simulation2.AppStateFn { - var bondDenom string - return simtestutil.AppStateFnWithExtendedCbs( - app.AppCodec(), - app.SimulationManager(), - app.ModuleBasics.DefaultGenesis(app.AppCodec()), - func(moduleName string, genesisState interface{}) { - if moduleName == stakingtypes.ModuleName { - stakingState := genesisState.(*stakingtypes.GenesisState) - bondDenom = stakingState.Params.BondDenom - } - }, - func(rawState map[string]json.RawMessage) { - - evmStateBz, ok := rawState[evmtypes.ModuleName] - if !ok { - panic("evm genesis state is missing") - } +func TestFullAppSimulation(t *testing.T) { + config := sim.NewConfigFromFlags() + config.ChainID = SimAppChainID + config.BlockMaxGas = SimBlockMaxGas + config.DBBackend = "memdb" + //config.ExportStatePath = "/Users/tanmay/.zetacored/simulation_state_export.json" - evmState := new(evmtypes.GenesisState) - app.AppCodec().MustUnmarshalJSON(evmStateBz, evmState) + db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "mem-db", "Simulation", sim.FlagVerboseValue, sim.FlagEnabledValue) + if skip { + t.Skip("skipping application simulation") + } + require.NoError(t, err, "simulation setup failed") - // we should replace the EvmDenom with BondDenom - evmState.Params.EvmDenom = bondDenom + defer func() { + require.NoError(t, db.Close()) + require.NoError(t, os.RemoveAll(dir)) + }() + appOptions := make(simtestutil.AppOptionsMap, 0) + appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue - // change appState back - rawState[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(evmState) - }, + app, err := NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + require.NoError(t, err) + + blockedAddresses := app.ModuleAccountAddrs() + _, _, simerr := simulation.SimulateFromSeed( + t, + os.Stdout, + app.BaseApp, + sim.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), + simulation2.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 + simtestutil.SimulationOperations(app, app.AppCodec(), config), + blockedAddresses, + config, + app.AppCodec(), ) + require.NoError(t, simerr) + + // check export works as expected + _, err = app.ExportAppStateAndValidators(false, nil, nil) + require.NoError(t, err) + + if config.Commit { + simtestutil.PrintStats(db) + } } diff --git a/sims.mk b/sims.mk index e48b22cf81..fb8a11d6de 100644 --- a/sims.mk +++ b/sims.mk @@ -17,25 +17,11 @@ test-sim-nondeterminism: @go test -mod=readonly $(SIMAPP) -run TestAppStateDeterminism -Enabled=true \ -NumBlocks=10 -BlockSize=20 -Commit=true -Period=0 -v -timeout 24h -test-sim-custom-genesis-fast: - @echo "Running custom genesis simulation..." - @echo "By default, ${HOME}/.zetacored/config/genesis.json will be used." - @go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation -Genesis=${HOME}/.gaia/config/genesis.json \ - -Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h - -test-sim-import-export: runsim - @echo "Running application import/export simulation. This may take several minutes..." - @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppImportExport - -test-sim-after-import: runsim - @echo "Running application simulation-after-import. This may take several minutes..." - @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppSimulationAfterImport - -test-sim-custom-genesis-multi-seed: runsim - @echo "Running multi-seed custom genesis simulation..." - @echo "By default, ${HOME}/.zetacored/config/genesis.json will be used." - @$(BINDIR)/runsim -Genesis=${HOME}/.gaia/config/genesis.json -SimAppPkg=$(SIMAPP) -ExitOnFail 400 5 TestFullAppSimulation +test-sim-fullappsimulation: + @echo "Running TestFullAppSimulation." + @go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation -Enabled=true \ + -NumBlocks=10 -BlockSize=20 -Commit=true -Period=0 -v -timeout 24h test-sim-multi-seed-long: runsim @echo "Running long multi-seed application simulation. This may take awhile!" @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestFullAppSimulation @@ -44,34 +30,11 @@ test-sim-multi-seed-short: runsim @echo "Running short multi-seed application simulation. This may take awhile!" @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation -test-sim-benchmark-invariants: - @echo "Running simulation invariant benchmarks..." - @go test -mod=readonly $(SIMAPP) -benchmem -bench=BenchmarkInvariants -run=^$ \ - -Enabled=true -NumBlocks=1000 -BlockSize=200 \ - -Period=1 -Commit=true -Seed=57 -v -timeout 24h + .PHONY: \ test-sim-nondeterminism \ -test-sim-custom-genesis-fast \ -test-sim-import-export \ -test-sim-after-import \ -test-sim-custom-genesis-multi-seed \ -test-sim-multi-seed-short \ +test-sim-fullappsimulation \ test-sim-multi-seed-long \ -test-sim-benchmark-invariants - -SIM_NUM_BLOCKS ?= 500 -SIM_BLOCK_SIZE ?= 200 -SIM_COMMIT ?= true - -test-sim-benchmark: - @echo "Running application benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!" - @go test -mod=readonly -benchmem -run=^$$ $(SIMAPP) -bench ^BenchmarkFullAppSimulation$$ \ - -Enabled=true -NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -timeout 24h - -test-sim-profile: - @echo "Running application benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!" - @go test -mod=readonly -benchmem -run=^$$ $(SIMAPP) -bench ^BenchmarkFullAppSimulation$$ \ - -Enabled=true -NumBlocks=$(SIM_NUM_BLOCKS) -BlockSize=$(SIM_BLOCK_SIZE) -Commit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out +test-sim-multi-seed-short -.PHONY: test-sim-profile test-sim-benchmark \ No newline at end of file From ac8fddf9c7dd333d5c62d8ae293ce8acf00b35f8 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 1 Oct 2024 20:35:56 +0530 Subject: [PATCH 05/59] move simulation tests to a separate directory --- app/modules.go | 44 +-------------------- sims.mk | 2 +- {app => tests/simulation}/sim/sim_config.go | 0 {app => tests/simulation}/sim/sim_state.go | 0 {app => tests/simulation}/sim/sim_utils.go | 0 {app => tests/simulation}/sim_test.go | 29 ++++++-------- 6 files changed, 16 insertions(+), 59 deletions(-) rename {app => tests/simulation}/sim/sim_config.go (100%) rename {app => tests/simulation}/sim/sim_state.go (100%) rename {app => tests/simulation}/sim/sim_utils.go (100%) rename {app => tests/simulation}/sim_test.go (88%) diff --git a/app/modules.go b/app/modules.go index 37151b717c..2d7fd82cb4 100644 --- a/app/modules.go +++ b/app/modules.go @@ -4,12 +4,10 @@ import ( "fmt" "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/auth" + authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" "github.com/cosmos/cosmos-sdk/x/bank" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -64,7 +62,7 @@ func simulationModules( _ bool, ) []module.AppModuleSimulation { return []module.AppModuleSimulation{ - auth.NewAppModule(appCodec, app.AccountKeeper, RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), //gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), @@ -84,41 +82,3 @@ func simulationModules( groupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), } } - -// RandomGenesisAccounts defines the default RandomGenesisAccountsFn used on the SDK. -// It creates a slice of BaseAccount, ContinuousVestingAccount and DelayedVestingAccount. -func RandomGenesisAccounts(simState *module.SimulationState) authtypes.GenesisAccounts { - genesisAccs := make(authtypes.GenesisAccounts, len(simState.Accounts)) - for i, acc := range simState.Accounts { - bacc := authtypes.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.Int64()))) - 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 -} diff --git a/sims.mk b/sims.mk index fb8a11d6de..5ce445832b 100644 --- a/sims.mk +++ b/sims.mk @@ -4,7 +4,7 @@ ### Simulations BINDIR ?= $(GOPATH)/bin -SIMAPP = ./app +SIMAPP = ./tests/simulation runsim: $(BINDIR)/runsim $(BINDIR)/runsim: diff --git a/app/sim/sim_config.go b/tests/simulation/sim/sim_config.go similarity index 100% rename from app/sim/sim_config.go rename to tests/simulation/sim/sim_config.go diff --git a/app/sim/sim_state.go b/tests/simulation/sim/sim_state.go similarity index 100% rename from app/sim/sim_state.go rename to tests/simulation/sim/sim_state.go diff --git a/app/sim/sim_utils.go b/tests/simulation/sim/sim_utils.go similarity index 100% rename from app/sim/sim_utils.go rename to tests/simulation/sim/sim_utils.go diff --git a/app/sim_test.go b/tests/simulation/sim_test.go similarity index 88% rename from app/sim_test.go rename to tests/simulation/sim_test.go index c13538f451..8fbd18d0db 100644 --- a/app/sim_test.go +++ b/tests/simulation/sim_test.go @@ -1,4 +1,4 @@ -package app_test +package simulation_test import ( "encoding/json" @@ -15,6 +15,7 @@ import ( evmante "github.com/zeta-chain/ethermint/app/ante" zetaapp "github.com/zeta-chain/node/app" "github.com/zeta-chain/node/app/ante" + sim2 "github.com/zeta-chain/node/tests/simulation/sim" dbm "github.com/cometbft/cometbft-db" @@ -27,16 +28,12 @@ import ( simulation2 "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli" - - // "github.com/cosmos/gaia/v11/app/helpers" - // "github.com/cosmos/gaia/v11/app/params" - "github.com/zeta-chain/node/app/sim" ) // AppChainID hardcoded chainID for simulation func init() { - sim.GetSimulatorFlags() + sim2.GetSimulatorFlags() } const ( @@ -95,11 +92,11 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { // TODO: Make another test for the fuzzer itself, which just has noOp txs // and doesn't depend on the application. func TestAppStateDeterminism(t *testing.T) { - if !sim.FlagEnabledValue { + if !sim2.FlagEnabledValue { t.Skip("skipping application simulation") } - config := sim.NewConfigFromFlags() + config := sim2.NewConfigFromFlags() config.InitialBlockHeight = 1 config.ExportParamsPath = "" config.OnOperation = false @@ -116,7 +113,7 @@ func TestAppStateDeterminism(t *testing.T) { appHashList := make([]json.RawMessage, numTimesToRunPerSeed) appOptions := make(simtestutil.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = sim2.FlagPeriodValue for i := 0; i < numSeeds; i++ { if config.Seed == simcli.DefaultSeedValue { @@ -127,7 +124,7 @@ func TestAppStateDeterminism(t *testing.T) { for j := 0; j < numTimesToRunPerSeed; j++ { var logger log.Logger - if sim.FlagVerboseValue { + if sim2.FlagVerboseValue { logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) } else { logger = log.NewNopLogger() @@ -151,7 +148,7 @@ func TestAppStateDeterminism(t *testing.T) { t, os.Stdout, app.BaseApp, - sim.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), + sim2.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), simulation2.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 simtestutil.SimulationOperations(app, app.AppCodec(), config), blockedAddresses, @@ -161,7 +158,7 @@ func TestAppStateDeterminism(t *testing.T) { require.NoError(t, err) if config.Commit { - sim.PrintStats(db) + sim2.PrintStats(db) } appHash := app.LastCommitID().Hash @@ -178,13 +175,13 @@ func TestAppStateDeterminism(t *testing.T) { } func TestFullAppSimulation(t *testing.T) { - config := sim.NewConfigFromFlags() + config := sim2.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas config.DBBackend = "memdb" //config.ExportStatePath = "/Users/tanmay/.zetacored/simulation_state_export.json" - db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "mem-db", "Simulation", sim.FlagVerboseValue, sim.FlagEnabledValue) + db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "mem-db", "Simulation", sim2.FlagVerboseValue, sim2.FlagEnabledValue) if skip { t.Skip("skipping application simulation") } @@ -195,7 +192,7 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, os.RemoveAll(dir)) }() appOptions := make(simtestutil.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = sim2.FlagPeriodValue app, err := NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) @@ -205,7 +202,7 @@ func TestFullAppSimulation(t *testing.T) { t, os.Stdout, app.BaseApp, - sim.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), + sim2.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), simulation2.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 simtestutil.SimulationOperations(app, app.AppCodec(), config), blockedAddresses, From b55f4396b50f71cdea641371da228a6517e6b233 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 1 Oct 2024 21:40:59 +0530 Subject: [PATCH 06/59] remove unused functions --- tests/simulation/sim/sim_utils.go | 64 +------------------------------ tests/simulation/sim_test.go | 57 ++++++++++++++------------- 2 files changed, 31 insertions(+), 90 deletions(-) diff --git a/tests/simulation/sim/sim_utils.go b/tests/simulation/sim/sim_utils.go index da915257f9..a54af7164a 100644 --- a/tests/simulation/sim/sim_utils.go +++ b/tests/simulation/sim/sim_utils.go @@ -1,76 +1,14 @@ package sim import ( - "encoding/json" "fmt" - "os" dbm "github.com/cometbft/cometbft-db" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/runtime" - "github.com/cosmos/cosmos-sdk/types/module" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - - zetaapp "github.com/zeta-chain/node/app" ) -// SimulationOperations retrieves the simulation params from the provided file path -// and returns all the modules weighted operations -func SimulationOperations(app *zetaapp.App, cdc codec.JSONCodec, config simtypes.Config) []simtypes.WeightedOperation { - simState := module.SimulationState{ - AppParams: make(simtypes.AppParams), - Cdc: cdc, - } - - if config.ParamsFile != "" { - bz, err := os.ReadFile(config.ParamsFile) - if err != nil { - panic(err) - } - - err = json.Unmarshal(bz, &simState.AppParams) - if err != nil { - panic(err) - } - } - - simState.LegacyProposalContents = app.SimulationManager().GetProposalContents(simState) //nolint:staticcheck - simState.ProposalMsgs = app.SimulationManager().GetProposalMsgs(simState) - return app.SimulationManager().WeightedOperations(simState) -} - -// CheckExportSimulation exports the app state and simulation parameters to JSON -// if the export paths are defined. -func CheckExportSimulation(app runtime.AppI, config simtypes.Config, params simtypes.Params) error { - if config.ExportStatePath != "" { - fmt.Println("exporting app state...") - exported, err := app.ExportAppStateAndValidators(false, nil, nil) - if err != nil { - return err - } - - if err := os.WriteFile(config.ExportStatePath, []byte(exported.AppState), 0o600); err != nil { - return err - } - } - - if config.ExportParamsPath != "" { - fmt.Println("exporting simulation params...") - paramsBz, err := json.MarshalIndent(params, "", " ") - if err != nil { - return err - } - - if err := os.WriteFile(config.ExportParamsPath, paramsBz, 0o600); err != nil { - return err - } - } - return nil -} - // PrintStats prints the corresponding statistics from the app DB. func PrintStats(db dbm.DB) { - fmt.Println("\nLevelDB Stats") + fmt.Println("\nDB Stats") fmt.Println(db.Stats()["leveldb.stats"]) fmt.Println("LevelDB cached block size", db.Stats()["leveldb.cachedblock"]) } diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 8fbd18d0db..934f57b82f 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -15,7 +15,7 @@ import ( evmante "github.com/zeta-chain/ethermint/app/ante" zetaapp "github.com/zeta-chain/node/app" "github.com/zeta-chain/node/app/ante" - sim2 "github.com/zeta-chain/node/tests/simulation/sim" + simutils "github.com/zeta-chain/node/tests/simulation/sim" dbm "github.com/cometbft/cometbft-db" @@ -24,16 +24,16 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/server" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - simulation2 "github.com/cosmos/cosmos-sdk/types/simulation" + cosmossimutils "github.com/cosmos/cosmos-sdk/testutil/sims" + cosmossim "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" - simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli" + cosmossimcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli" ) // AppChainID hardcoded chainID for simulation func init() { - sim2.GetSimulatorFlags() + simutils.GetSimulatorFlags() } const ( @@ -92,31 +92,32 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { // TODO: Make another test for the fuzzer itself, which just has noOp txs // and doesn't depend on the application. func TestAppStateDeterminism(t *testing.T) { - if !sim2.FlagEnabledValue { + if !simutils.FlagEnabledValue { t.Skip("skipping application simulation") } - config := sim2.NewConfigFromFlags() + config := simutils.NewConfigFromFlags() config.InitialBlockHeight = 1 config.ExportParamsPath = "" config.OnOperation = false config.AllInvariants = false config.ChainID = SimAppChainID + config.DBBackend = "goleveldb" numSeeds := 3 numTimesToRunPerSeed := 5 // We will be overriding the random seed and just run a single simulation on the provided seed value - if config.Seed != simcli.DefaultSeedValue { + if config.Seed != cosmossimcli.DefaultSeedValue { numSeeds = 1 } appHashList := make([]json.RawMessage, numTimesToRunPerSeed) - appOptions := make(simtestutil.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = sim2.FlagPeriodValue + appOptions := make(cosmossimutils.AppOptionsMap, 0) + appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue for i := 0; i < numSeeds; i++ { - if config.Seed == simcli.DefaultSeedValue { + if config.Seed == cosmossimcli.DefaultSeedValue { config.Seed = rand.Int63() } @@ -124,14 +125,16 @@ func TestAppStateDeterminism(t *testing.T) { for j := 0; j < numTimesToRunPerSeed; j++ { var logger log.Logger - if sim2.FlagVerboseValue { + if simutils.FlagVerboseValue { logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) } else { logger = log.NewNopLogger() } - db := dbm.NewMemDB() - dir, err := os.MkdirTemp("", "zeta-simulation") + db, dir, logger, skip, err := cosmossimutils.SetupSimulation(config, "level-db", "Simulation", simutils.FlagVerboseValue, simutils.FlagEnabledValue) + if skip { + t.Skip("skipping application simulation") + } require.NoError(t, err) appOptions[flags.FlagHome] = dir @@ -148,9 +151,9 @@ func TestAppStateDeterminism(t *testing.T) { t, os.Stdout, app.BaseApp, - sim2.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), - simulation2.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 - simtestutil.SimulationOperations(app, app.AppCodec(), config), + simutils.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), + cosmossim.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 + cosmossimutils.SimulationOperations(app, app.AppCodec(), config), blockedAddresses, config, app.AppCodec(), @@ -158,7 +161,7 @@ func TestAppStateDeterminism(t *testing.T) { require.NoError(t, err) if config.Commit { - sim2.PrintStats(db) + simutils.PrintStats(db) } appHash := app.LastCommitID().Hash @@ -175,13 +178,13 @@ func TestAppStateDeterminism(t *testing.T) { } func TestFullAppSimulation(t *testing.T) { - config := sim2.NewConfigFromFlags() + config := simutils.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas - config.DBBackend = "memdb" + config.DBBackend = "goleveldb" //config.ExportStatePath = "/Users/tanmay/.zetacored/simulation_state_export.json" - db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "mem-db", "Simulation", sim2.FlagVerboseValue, sim2.FlagEnabledValue) + db, dir, logger, skip, err := cosmossimutils.SetupSimulation(config, "level-db", "Simulation", simutils.FlagVerboseValue, simutils.FlagEnabledValue) if skip { t.Skip("skipping application simulation") } @@ -191,8 +194,8 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, db.Close()) require.NoError(t, os.RemoveAll(dir)) }() - appOptions := make(simtestutil.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = sim2.FlagPeriodValue + appOptions := make(cosmossimutils.AppOptionsMap, 0) + appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue app, err := NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) @@ -202,9 +205,9 @@ func TestFullAppSimulation(t *testing.T) { t, os.Stdout, app.BaseApp, - sim2.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), - simulation2.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 - simtestutil.SimulationOperations(app, app.AppCodec(), config), + simutils.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), + cosmossim.RandomAccounts, + cosmossimutils.SimulationOperations(app, app.AppCodec(), config), blockedAddresses, config, app.AppCodec(), @@ -216,6 +219,6 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, err) if config.Commit { - simtestutil.PrintStats(db) + cosmossimutils.PrintStats(db) } } From 913aa19802d558565ab4d2a412f4eba47c18d3f9 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 2 Oct 2024 17:11:05 +0530 Subject: [PATCH 07/59] add comments --- sims.mk | 7 +- tests/simulation/sim/sim_state.go | 5 +- tests/simulation/sim_test.go | 111 +++++++------- testutil/simapp/default_constants.go | 25 --- testutil/simapp/simapp.go | 219 --------------------------- 5 files changed, 66 insertions(+), 301 deletions(-) delete mode 100644 testutil/simapp/default_constants.go delete mode 100644 testutil/simapp/simapp.go diff --git a/sims.mk b/sims.mk index 5ce445832b..65301e0e9e 100644 --- a/sims.mk +++ b/sims.mk @@ -6,6 +6,8 @@ BINDIR ?= $(GOPATH)/bin SIMAPP = ./tests/simulation + +# Run sim is a cosmos tool which helps us to run multiple simulations in parallel. runsim: $(BINDIR)/runsim $(BINDIR)/runsim: @echo "Installing runsim..." @@ -15,13 +17,14 @@ $(BINDIR)/runsim: test-sim-nondeterminism: @echo "Running non-determinism test..." @go test -mod=readonly $(SIMAPP) -run TestAppStateDeterminism -Enabled=true \ - -NumBlocks=10 -BlockSize=20 -Commit=true -Period=0 -v -timeout 24h + -NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h test-sim-fullappsimulation: @echo "Running TestFullAppSimulation." @go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation -Enabled=true \ - -NumBlocks=10 -BlockSize=20 -Commit=true -Period=0 -v -timeout 24h + -NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h + test-sim-multi-seed-long: runsim @echo "Running long multi-seed application simulation. This may take awhile!" @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestFullAppSimulation diff --git a/tests/simulation/sim/sim_state.go b/tests/simulation/sim/sim_state.go index 12df57dc5c..8b4d73a0c6 100644 --- a/tests/simulation/sim/sim_state.go +++ b/tests/simulation/sim/sim_state.go @@ -107,9 +107,9 @@ func AppStateFn(cdc codec.Codec, simManager *module.SimulationManager, genesisSt notBondedTokens = notBondedTokens.Add(val.GetTokens()) } notBondedCoins := sdk.NewCoin(stakingState.Params.BondDenom, notBondedTokens) + // edit bank state to make it have the not bonded pool tokens bankStateBz, ok := rawState[banktypes.ModuleName] - // TODO(fdymylja/jonathan): should we panic in this case if !ok { panic("bank genesis state is missing") } @@ -134,6 +134,7 @@ func AppStateFn(cdc codec.Codec, simManager *module.SimulationManager, genesisSt }) } + // Set the bond denom in the EVM genesis state evmStateBz, ok := rawState[evmtypes.ModuleName] if !ok { panic("evm genesis state is missing") @@ -207,8 +208,6 @@ func AppStateRandomizedFn( GenTimestamp: genesisTimestamp, } - fmt.Println("Generating genesis states...") - simManager.GenerateGenesisStates(simState) appState, err := json.Marshal(genesisState) diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 934f57b82f..4efb6a1646 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -39,14 +39,16 @@ func init() { const ( SimAppChainID = "simulation_777-1" SimBlockMaxGas = 815000000 - TestAppChainID = "zetachain_777-1" + SimDBBackend = "goleveldb" + SimDBName = "simulation" ) -// NewSimApp disable feemarket on native tx, otherwise the cosmos-sdk simulation tests will fail. func NewSimApp(logger log.Logger, db dbm.DB, appOptions servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp)) (*zetaapp.App, error) { encCdc := zetaapp.MakeEncodingConfig() - app := zetaapp.New( + + // Set load latest version to false as we manually set it later. + zetaApp := zetaapp.New( logger, db, nil, @@ -58,17 +60,20 @@ func NewSimApp(logger log.Logger, db dbm.DB, appOptions servertypes.AppOptions, appOptions, baseAppOptions..., ) + + // Set power reduction to 1 to make sure all bonded validators are added to the validator set sdk.DefaultPowerReduction = sdk.OneInt() - // disable feemarket on native tx + + // use zeta antehandler options := ante.HandlerOptions{ - AccountKeeper: app.AccountKeeper, - BankKeeper: app.BankKeeper, - EvmKeeper: app.EvmKeeper, - FeeMarketKeeper: app.FeeMarketKeeper, + AccountKeeper: zetaApp.AccountKeeper, + BankKeeper: zetaApp.BankKeeper, + EvmKeeper: zetaApp.EvmKeeper, + FeeMarketKeeper: zetaApp.FeeMarketKeeper, SignModeHandler: encCdc.TxConfig.SignModeHandler(), SigGasConsumer: evmante.DefaultSigVerificationGasConsumer, MaxTxGasWanted: 0, - ObserverKeeper: app.ObserverKeeper, + ObserverKeeper: zetaApp.ObserverKeeper, } anteHandler, err := ante.NewAnteHandler(options) @@ -76,11 +81,11 @@ func NewSimApp(logger log.Logger, db dbm.DB, appOptions servertypes.AppOptions, panic(err) } - app.SetAnteHandler(anteHandler) - if err := app.LoadLatestVersion(); err != nil { + zetaApp.SetAnteHandler(anteHandler) + if err := zetaApp.LoadLatestVersion(); err != nil { return nil, err } - return app, nil + return zetaApp, nil } // interBlockCacheOpt returns a BaseApp option function that sets the persistent @@ -89,20 +94,24 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager()) } -// TODO: Make another test for the fuzzer itself, which just has noOp txs -// and doesn't depend on the application. +// TestAppStateDeterminism runs a full application simulation , and produces multiple blocks as per the config +// It checks the determinism of the application by comparing the apphash at the end of each run to other runs +// The following test certifies that , for the same set of operations ( irrespective of what the operations are ) , +// we would reach the same final state func TestAppStateDeterminism(t *testing.T) { if !simutils.FlagEnabledValue { t.Skip("skipping application simulation") } config := simutils.NewConfigFromFlags() + config.InitialBlockHeight = 1 config.ExportParamsPath = "" config.OnOperation = false config.AllInvariants = false config.ChainID = SimAppChainID - config.DBBackend = "goleveldb" + config.DBBackend = SimDBBackend + config.BlockMaxGas = SimBlockMaxGas numSeeds := 3 numTimesToRunPerSeed := 5 @@ -112,59 +121,51 @@ func TestAppStateDeterminism(t *testing.T) { numSeeds = 1 } + // For the same seed, the app hash produced at the end of each run should be the same appHashList := make([]json.RawMessage, numTimesToRunPerSeed) + appOptions := make(cosmossimutils.AppOptionsMap, 0) appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue + fmt.Println("Running tests for numSeeds: ", numSeeds, " numTimesToRunPerSeed: ", numTimesToRunPerSeed) + for i := 0; i < numSeeds; i++ { if config.Seed == cosmossimcli.DefaultSeedValue { config.Seed = rand.Int63() } - fmt.Println("config.Seed: ", config.Seed) - + //dbPrefix := fmt.Sprintf("%s-%d", SimDBBackend, i) + // For the same seed, the app hash produced at the end of each run should be the same for j := 0; j < numTimesToRunPerSeed; j++ { - var logger log.Logger - if simutils.FlagVerboseValue { - logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - } else { - logger = log.NewNopLogger() - } - - db, dir, logger, skip, err := cosmossimutils.SetupSimulation(config, "level-db", "Simulation", simutils.FlagVerboseValue, simutils.FlagEnabledValue) - if skip { - t.Skip("skipping application simulation") - } + db, dir, logger, _, err := cosmossimutils.SetupSimulation(config, SimDBBackend, SimDBName, simutils.FlagVerboseValue, simutils.FlagEnabledValue) require.NoError(t, err) appOptions[flags.FlagHome] = dir - app, err := NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) fmt.Printf( "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n", config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed, ) - blockedAddresses := app.ModuleAccountAddrs() + blockedAddresses := simApp.ModuleAccountAddrs() _, _, err = simulation.SimulateFromSeed( t, os.Stdout, - app.BaseApp, - simutils.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), - cosmossim.RandomAccounts, // Replace with own random account function if using keys other than secp256k1 - cosmossimutils.SimulationOperations(app, app.AppCodec(), config), + simApp.BaseApp, + simutils.AppStateFn(simApp.AppCodec(), simApp.SimulationManager(), simApp.ModuleBasics.DefaultGenesis(simApp.AppCodec())), + cosmossim.RandomAccounts, + cosmossimutils.SimulationOperations(simApp, simApp.AppCodec(), config), blockedAddresses, config, - app.AppCodec(), + simApp.AppCodec(), ) require.NoError(t, err) - if config.Commit { - simutils.PrintStats(db) - } + simutils.PrintStats(db) - appHash := app.LastCommitID().Hash + appHash := simApp.LastCommitID().Hash appHashList[j] = appHash if j != 0 { @@ -177,14 +178,17 @@ func TestAppStateDeterminism(t *testing.T) { } } +// TestFullAppSimulation runs a full app simulation with the provided configuration. +// At the end of the run it tries to export the genesis state to make sure the export works. func TestFullAppSimulation(t *testing.T) { + config := simutils.NewConfigFromFlags() + config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas - config.DBBackend = "goleveldb" - //config.ExportStatePath = "/Users/tanmay/.zetacored/simulation_state_export.json" + config.DBBackend = SimDBBackend - db, dir, logger, skip, err := cosmossimutils.SetupSimulation(config, "level-db", "Simulation", simutils.FlagVerboseValue, simutils.FlagEnabledValue) + db, dir, logger, skip, err := cosmossimutils.SetupSimulation(config, SimDBBackend, SimDBName, simutils.FlagVerboseValue, simutils.FlagEnabledValue) if skip { t.Skip("skipping application simulation") } @@ -196,29 +200,32 @@ func TestFullAppSimulation(t *testing.T) { }() appOptions := make(cosmossimutils.AppOptionsMap, 0) appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue + appOptions[flags.FlagHome] = dir - app, err := NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) - blockedAddresses := app.ModuleAccountAddrs() + blockedAddresses := simApp.ModuleAccountAddrs() _, _, simerr := simulation.SimulateFromSeed( t, os.Stdout, - app.BaseApp, - simutils.AppStateFn(app.AppCodec(), app.SimulationManager(), app.ModuleBasics.DefaultGenesis(app.AppCodec())), + simApp.BaseApp, + simutils.AppStateFn(simApp.AppCodec(), simApp.SimulationManager(), simApp.ModuleBasics.DefaultGenesis(simApp.AppCodec())), cosmossim.RandomAccounts, - cosmossimutils.SimulationOperations(app, app.AppCodec(), config), + cosmossimutils.SimulationOperations(simApp, simApp.AppCodec(), config), blockedAddresses, config, - app.AppCodec(), + simApp.AppCodec(), ) require.NoError(t, simerr) // check export works as expected - _, err = app.ExportAppStateAndValidators(false, nil, nil) + exported, err := simApp.ExportAppStateAndValidators(false, nil, nil) require.NoError(t, err) - - if config.Commit { - cosmossimutils.PrintStats(db) + if config.ExportStatePath != "" { + err := os.WriteFile(config.ExportStatePath, exported.AppState, 0o600) + require.NoError(t, err) } + + cosmossimutils.PrintStats(db) } diff --git a/testutil/simapp/default_constants.go b/testutil/simapp/default_constants.go deleted file mode 100644 index c4398ad7bb..0000000000 --- a/testutil/simapp/default_constants.go +++ /dev/null @@ -1,25 +0,0 @@ -package simapp - -import ( - "time" - - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmtypes "github.com/cometbft/cometbft/types" -) - -var defaultConsensusParams = &tmproto.ConsensusParams{ - Block: &tmproto.BlockParams{ - MaxBytes: 200000, - MaxGas: 2000000, - }, - Evidence: &tmproto.EvidenceParams{ - MaxAgeNumBlocks: 302400, - MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration - MaxBytes: 10000, - }, - Validator: &tmproto.ValidatorParams{ - PubKeyTypes: []string{ - tmtypes.ABCIPubKeyTypeEd25519, - }, - }, -} diff --git a/testutil/simapp/simapp.go b/testutil/simapp/simapp.go deleted file mode 100644 index b42b0b5f1a..0000000000 --- a/testutil/simapp/simapp.go +++ /dev/null @@ -1,219 +0,0 @@ -package simapp - -import ( - "encoding/json" - "testing" - "time" - - tmdb "github.com/cometbft/cometbft-db" - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/libs/log" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmtypes "github.com/cometbft/cometbft/types" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/stretchr/testify/require" - - "github.com/zeta-chain/node/app" - "github.com/zeta-chain/node/cmd/zetacored/config" - types2 "github.com/zeta-chain/node/x/emissions/types" -) - -func Setup(isCheckTx bool) *app.App { - app, genesisState := setup(!isCheckTx, 5) - if !isCheckTx { - // init chain must be called to stop deliverState from being nil - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - if err != nil { - panic(err) - } - - // Initialize the chain - app.InitChain( - abci.RequestInitChain{ - ChainId: "simnet_101-1", - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: defaultConsensusParams, - AppStateBytes: stateBytes, - }, - ) - } - - return app -} - -func setup(withGenesis bool, invCheckPeriod uint) (*app.App, app.GenesisState) { - db := tmdb.NewMemDB() - encCdc := app.MakeEncodingConfig() - a := app.New( - log.NewNopLogger(), - db, - nil, - true, - map[int64]bool{}, - app.DefaultNodeHome, - invCheckPeriod, - encCdc, - simtestutil.EmptyAppOptions{}, - ) - if withGenesis { - return a, app.NewDefaultGenesisState(encCdc.Codec) - } - return a, app.GenesisState{} -} - -func SetupWithGenesisValSet( - t *testing.T, - valSet *tmtypes.ValidatorSet, - genDelAccs []authtypes.GenesisAccount, - bondAmt sdk.Int, - emissionParams types2.Params, - genDelBalances []banktypes.Balance, - genBalances []banktypes.Balance, -) *app.App { - app, genesisState := setup(true, 5) - // set genesis accounts - authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genDelAccs) - genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) - - validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) - delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) - // Make all members of valSet as validators - // Make all members of delSet as delegators to each of the validators - for _, val := range valSet.Validators { - pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) - require.NoError(t, err) - pkAny, err := codectypes.NewAnyWithValue(pk) - require.NoError(t, err) - validator := stakingtypes.Validator{ - OperatorAddress: sdk.ValAddress(val.Address).String(), - ConsensusPubkey: pkAny, - Jailed: false, - Status: stakingtypes.Bonded, - Tokens: bondAmt, - DelegatorShares: sdk.OneDec(), - Description: stakingtypes.Description{}, - UnbondingHeight: int64(0), - UnbondingTime: time.Unix(0, 0).UTC(), - Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), - MinSelfDelegation: sdk.ZeroInt(), - } - validators = append(validators, validator) - delegations = append( - delegations, - stakingtypes.NewDelegation(genDelAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()), - ) - } - - emissionsGenesis := types2.DefaultGenesis() - emissionsGenesis.Params = emissionParams - genesisState[types2.ModuleName] = app.AppCodec().MustMarshalJSON(emissionsGenesis) - // set validators and delegations - params := stakingtypes.DefaultParams() - params.BondDenom = config.BaseDenom - stakingGenesis := stakingtypes.NewGenesisState(params, validators, delegations) - genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis) - - totalSupply := sdk.NewCoins() - // genDelBalances contains additional balances for delegators - // Add Bond amount and additional coins for these addresses - - for _, b := range genDelBalances { - // add genesis acc tokens and delegated tokens to total supply - totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(config.BaseDenom, bondAmt))...) - } - // add balances for non delegator accounts - // Add only external balances - for _, b := range genBalances { - // add genesis acc tokens and delegated tokens to total supply - totalSupply = totalSupply.Add(b.Coins...) - } - - totalBalances := []banktypes.Balance{} - // Add extra balance to account for delegator bonded pool - totalBalances = append(append(append(totalBalances, genBalances...), genDelBalances...), banktypes.Balance{ - Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), - Coins: sdk.Coins{sdk.NewCoin(config.BaseDenom, bondAmt)}, - }) - - // update total supply - - bankGenesis := banktypes.NewGenesisState( - banktypes.DefaultGenesisState().Params, - totalBalances, - totalSupply, - []banktypes.Metadata{}, - []banktypes.SendEnabled{}, - ) - genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) - - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - require.NoError(t, err) - - // init chain will set the validator set and initialize the genesis accounts - app.InitChain( - abci.RequestInitChain{ - ChainId: "simnet_101-1", - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: defaultConsensusParams, - AppStateBytes: stateBytes, - }, - ) - - // commit genesis changes - app.Commit() - - app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{ - Height: app.LastBlockHeight() + 1, - AppHash: app.LastCommitID().Hash, - ValidatorsHash: valSet.Hash(), - NextValidatorsHash: valSet.Hash(), - ChainID: "simnet_101-1", - }}) - - return app -} - -func SetupWithGenesisAccounts(genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *app.App { - app, genesisState := setup(true, 0) - authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) - genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) - - totalSupply := sdk.NewCoins() - for _, b := range balances { - totalSupply = totalSupply.Add(b.Coins...) - } - - bankGenesis := banktypes.NewGenesisState( - banktypes.DefaultGenesisState().Params, - balances, - totalSupply, - []banktypes.Metadata{}, - []banktypes.SendEnabled{}, - ) - genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) - - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - if err != nil { - panic(err) - } - - app.InitChain( - abci.RequestInitChain{ - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: defaultConsensusParams, - AppStateBytes: stateBytes, - }, - ) - - app.Commit() - - app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1}}) - - return app -} From 10d8a38ef9d4b8022761aad6f0f9dfef03d00660 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 2 Oct 2024 19:53:41 +0530 Subject: [PATCH 08/59] enable gov module --- app/modules.go | 2 +- sims.mk | 2 +- tests/simulation/sim/sim_state.go | 3 ++ tests/simulation/sim/sim_utils.go | 49 +++++++++++++++++++++++ tests/simulation/sim_test.go | 64 ++----------------------------- 5 files changed, 58 insertions(+), 62 deletions(-) diff --git a/app/modules.go b/app/modules.go index 2d7fd82cb4..a2a6a90200 100644 --- a/app/modules.go +++ b/app/modules.go @@ -64,7 +64,7 @@ func simulationModules( return []module.AppModuleSimulation{ auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), - //gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), + gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), slashing.NewAppModule( diff --git a/sims.mk b/sims.mk index 65301e0e9e..db4b4d7a5c 100644 --- a/sims.mk +++ b/sims.mk @@ -17,7 +17,7 @@ $(BINDIR)/runsim: test-sim-nondeterminism: @echo "Running non-determinism test..." @go test -mod=readonly $(SIMAPP) -run TestAppStateDeterminism -Enabled=true \ - -NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h + -NumBlocks=10 -BlockSize=20 -Commit=true -Period=0 -v -timeout 24h test-sim-fullappsimulation: diff --git a/tests/simulation/sim/sim_state.go b/tests/simulation/sim/sim_state.go index 8b4d73a0c6..c4f884b9b4 100644 --- a/tests/simulation/sim/sim_state.go +++ b/tests/simulation/sim/sim_state.go @@ -188,6 +188,9 @@ func AppStateRandomizedFn( numInitiallyBonded = numAccs } + // Set the default power reduction to be one less than the initial stake so that all randomised validators are part of the validator set + sdk.DefaultPowerReduction = initialStake.Sub(sdk.OneInt()) + fmt.Printf( `Selected randomly generated parameters for simulated genesis: { diff --git a/tests/simulation/sim/sim_utils.go b/tests/simulation/sim/sim_utils.go index a54af7164a..56a73f17af 100644 --- a/tests/simulation/sim/sim_utils.go +++ b/tests/simulation/sim/sim_utils.go @@ -4,8 +4,57 @@ import ( "fmt" dbm "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/libs/log" + "github.com/cosmos/cosmos-sdk/baseapp" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/zeta-chain/ethermint/app" + evmante "github.com/zeta-chain/ethermint/app/ante" + zetaapp "github.com/zeta-chain/node/app" + "github.com/zeta-chain/node/app/ante" ) +func NewSimApp(logger log.Logger, db dbm.DB, appOptions servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp)) (*zetaapp.App, error) { + + encCdc := zetaapp.MakeEncodingConfig() + + // Set load latest version to false as we manually set it later. + zetaApp := zetaapp.New( + logger, + db, + nil, + false, + map[int64]bool{}, + app.DefaultNodeHome, + 5, + encCdc, + appOptions, + baseAppOptions..., + ) + + // use zeta antehandler + options := ante.HandlerOptions{ + AccountKeeper: zetaApp.AccountKeeper, + BankKeeper: zetaApp.BankKeeper, + EvmKeeper: zetaApp.EvmKeeper, + FeeMarketKeeper: zetaApp.FeeMarketKeeper, + SignModeHandler: encCdc.TxConfig.SignModeHandler(), + SigGasConsumer: evmante.DefaultSigVerificationGasConsumer, + MaxTxGasWanted: 0, + ObserverKeeper: zetaApp.ObserverKeeper, + } + + anteHandler, err := ante.NewAnteHandler(options) + if err != nil { + panic(err) + } + + zetaApp.SetAnteHandler(anteHandler) + if err := zetaApp.LoadLatestVersion(); err != nil { + return nil, err + } + return zetaApp, nil +} + // PrintStats prints the corresponding statistics from the app DB. func PrintStats(db dbm.DB) { fmt.Println("\nDB Stats") diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 4efb6a1646..a7fb801b9d 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -7,18 +7,9 @@ import ( "os" "testing" - "github.com/cometbft/cometbft/libs/log" - servertypes "github.com/cosmos/cosmos-sdk/server/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/zeta-chain/ethermint/app" - evmante "github.com/zeta-chain/ethermint/app/ante" - zetaapp "github.com/zeta-chain/node/app" - "github.com/zeta-chain/node/app/ante" simutils "github.com/zeta-chain/node/tests/simulation/sim" - dbm "github.com/cometbft/cometbft-db" - "github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/baseapp" @@ -43,51 +34,6 @@ const ( SimDBName = "simulation" ) -func NewSimApp(logger log.Logger, db dbm.DB, appOptions servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp)) (*zetaapp.App, error) { - - encCdc := zetaapp.MakeEncodingConfig() - - // Set load latest version to false as we manually set it later. - zetaApp := zetaapp.New( - logger, - db, - nil, - false, - map[int64]bool{}, - app.DefaultNodeHome, - 5, - encCdc, - appOptions, - baseAppOptions..., - ) - - // Set power reduction to 1 to make sure all bonded validators are added to the validator set - sdk.DefaultPowerReduction = sdk.OneInt() - - // use zeta antehandler - options := ante.HandlerOptions{ - AccountKeeper: zetaApp.AccountKeeper, - BankKeeper: zetaApp.BankKeeper, - EvmKeeper: zetaApp.EvmKeeper, - FeeMarketKeeper: zetaApp.FeeMarketKeeper, - SignModeHandler: encCdc.TxConfig.SignModeHandler(), - SigGasConsumer: evmante.DefaultSigVerificationGasConsumer, - MaxTxGasWanted: 0, - ObserverKeeper: zetaApp.ObserverKeeper, - } - - anteHandler, err := ante.NewAnteHandler(options) - if err != nil { - panic(err) - } - - zetaApp.SetAnteHandler(anteHandler) - if err := zetaApp.LoadLatestVersion(); err != nil { - return nil, err - } - return zetaApp, nil -} - // interBlockCacheOpt returns a BaseApp option function that sets the persistent // inter-block write-through cache. func interBlockCacheOpt() func(*baseapp.BaseApp) { @@ -97,7 +43,7 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { // TestAppStateDeterminism runs a full application simulation , and produces multiple blocks as per the config // It checks the determinism of the application by comparing the apphash at the end of each run to other runs // The following test certifies that , for the same set of operations ( irrespective of what the operations are ) , -// we would reach the same final state +// we would reach the same final state if the initital state is the same func TestAppStateDeterminism(t *testing.T) { if !simutils.FlagEnabledValue { t.Skip("skipping application simulation") @@ -121,7 +67,6 @@ func TestAppStateDeterminism(t *testing.T) { numSeeds = 1 } - // For the same seed, the app hash produced at the end of each run should be the same appHashList := make([]json.RawMessage, numTimesToRunPerSeed) appOptions := make(cosmossimutils.AppOptionsMap, 0) @@ -133,15 +78,13 @@ func TestAppStateDeterminism(t *testing.T) { if config.Seed == cosmossimcli.DefaultSeedValue { config.Seed = rand.Int63() } - - //dbPrefix := fmt.Sprintf("%s-%d", SimDBBackend, i) // For the same seed, the app hash produced at the end of each run should be the same for j := 0; j < numTimesToRunPerSeed; j++ { db, dir, logger, _, err := cosmossimutils.SetupSimulation(config, SimDBBackend, SimDBName, simutils.FlagVerboseValue, simutils.FlagEnabledValue) require.NoError(t, err) appOptions[flags.FlagHome] = dir - simApp, err := NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := simutils.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) fmt.Printf( "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n", @@ -150,6 +93,7 @@ func TestAppStateDeterminism(t *testing.T) { blockedAddresses := simApp.ModuleAccountAddrs() + // Random seed is used to produce a random initial state for the simulation _, _, err = simulation.SimulateFromSeed( t, os.Stdout, @@ -202,7 +146,7 @@ func TestFullAppSimulation(t *testing.T) { appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := simutils.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) blockedAddresses := simApp.ModuleAccountAddrs() From 49d430cf725f9235ce037c169b12f3f2ad63de0d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 2 Oct 2024 19:57:05 +0530 Subject: [PATCH 09/59] enable gov module --- tests/simulation/sim/sim_utils.go | 2 +- tests/simulation/sim_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/simulation/sim/sim_utils.go b/tests/simulation/sim/sim_utils.go index 56a73f17af..a1e25fb8d7 100644 --- a/tests/simulation/sim/sim_utils.go +++ b/tests/simulation/sim/sim_utils.go @@ -59,5 +59,5 @@ func NewSimApp(logger log.Logger, db dbm.DB, appOptions servertypes.AppOptions, func PrintStats(db dbm.DB) { fmt.Println("\nDB Stats") fmt.Println(db.Stats()["leveldb.stats"]) - fmt.Println("LevelDB cached block size", db.Stats()["leveldb.cachedblock"]) + fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) } diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index a7fb801b9d..ffb48f1f95 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -171,5 +171,5 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, err) } - cosmossimutils.PrintStats(db) + simutils.PrintStats(db) } From 73fbcf5d21156881a6a0912c37e0458e11fac893 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 2 Oct 2024 22:01:31 +0530 Subject: [PATCH 10/59] fix lint error --- app/encoding.go | 1 + app/modules.go | 34 +++++++++++++++--- changelog.md | 1 + e2e/runner/admin_evm.go | 6 ++-- e2e/runner/report.go | 2 +- tests/simulation/sim/sim_config.go | 56 +++++++++++++++++++++++++----- tests/simulation/sim/sim_state.go | 32 ++++++++++++++--- tests/simulation/sim/sim_utils.go | 9 +++-- tests/simulation/sim_test.go | 47 +++++++++++++++++++++---- 9 files changed, 157 insertions(+), 31 deletions(-) diff --git a/app/encoding.go b/app/encoding.go index dbf32a0878..2e8c728b0f 100644 --- a/app/encoding.go +++ b/app/encoding.go @@ -14,6 +14,7 @@ import ( evmenc "github.com/zeta-chain/ethermint/encoding" ethermint "github.com/zeta-chain/ethermint/types" evmtypes "github.com/zeta-chain/ethermint/x/evm/types" + authoritytypes "github.com/zeta-chain/node/x/authority/types" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" emissionstypes "github.com/zeta-chain/node/x/emissions/types" diff --git a/app/modules.go b/app/modules.go index a2a6a90200..c94872305b 100644 --- a/app/modules.go +++ b/app/modules.go @@ -32,7 +32,7 @@ import ( // non-dependant module elements, such as codec registration // and genesis verification. func newBasicManagerFromManager(app *App) module.BasicManager { - var moduleBasics []module.AppModuleBasic + moduleBasics := make([]module.AppModuleBasic, 0) for _, m := range app.mm.Modules { m, ok := m.(module.AppModuleBasic) if !ok { @@ -62,11 +62,35 @@ func simulationModules( _ bool, ) []module.AppModuleSimulation { return []module.AppModuleSimulation{ - auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + auth.NewAppModule( + appCodec, + app.AccountKeeper, + authsims.RandomGenesisAccounts, + app.GetSubspace(authtypes.ModuleName), + ), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), - gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), - staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), - distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), + gov.NewAppModule( + appCodec, + &app.GovKeeper, + app.AccountKeeper, + app.BankKeeper, + app.GetSubspace(govtypes.ModuleName), + ), + staking.NewAppModule( + appCodec, + app.StakingKeeper, + app.AccountKeeper, + app.BankKeeper, + app.GetSubspace(stakingtypes.ModuleName), + ), + distr.NewAppModule( + appCodec, + app.DistrKeeper, + app.AccountKeeper, + app.BankKeeper, + app.StakingKeeper, + app.GetSubspace(distrtypes.ModuleName), + ), slashing.NewAppModule( appCodec, app.SlashingKeeper, diff --git a/changelog.md b/changelog.md index d78c1861ae..6069bac909 100644 --- a/changelog.md +++ b/changelog.md @@ -36,6 +36,7 @@ * [2874](https://github.com/zeta-chain/node/pull/2874) - add support for multiple runs for precompile tests * [2895](https://github.com/zeta-chain/node/pull/2895) - add e2e test for bitcoin deposit and call * [2894](https://github.com/zeta-chain/node/pull/2894) - increase gas limit for TSS vote tx +* [2947](https://github.com/zeta-chain/node/pull/2947/) - add simulation tests ### Fixes diff --git a/e2e/runner/admin_evm.go b/e2e/runner/admin_evm.go index a373f2325a..ed3f682d0b 100644 --- a/e2e/runner/admin_evm.go +++ b/e2e/runner/admin_evm.go @@ -1,8 +1,6 @@ package runner import ( - "fmt" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/stretchr/testify/require" @@ -14,7 +12,7 @@ func (r *E2ERunner) UpdateTssAddressForConnector() { tx, err := r.ConnectorEth.UpdateTssAddress(r.EVMAuth, r.TSSAddress) require.NoError(r, err) - r.Logger.Info(fmt.Sprintf("TSS Address Update Tx: %s", tx.Hash().String())) + r.Logger.Info("TSS Address Update Tx: %s", tx.Hash().String()) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) utils.RequireTxSuccessful(r, receipt) @@ -28,7 +26,7 @@ func (r *E2ERunner) UpdateTssAddressForErc20custody() { tx, err := r.ERC20Custody.UpdateTSSAddress(r.EVMAuth, r.TSSAddress) require.NoError(r, err) - r.Logger.Info(fmt.Sprintf("TSS ERC20 Address Update Tx: %s", tx.Hash().String())) + r.Logger.Info("TSS ERC20 Address Update Tx: %s", tx.Hash().String()) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) utils.RequireTxSuccessful(r, receipt) diff --git a/e2e/runner/report.go b/e2e/runner/report.go index c860f014b1..b36e3033bc 100644 --- a/e2e/runner/report.go +++ b/e2e/runner/report.go @@ -59,7 +59,7 @@ func (r *E2ERunner) PrintTestReports(tr TestReports) { if err != nil { r.Logger.Print("Error rendering test report: %s", err) } - r.Logger.PrintNoPrefix(table) + r.Logger.PrintNoPrefix("%s", table) } // NetworkReport is a struct that contains the report for the network used after running e2e tests diff --git a/tests/simulation/sim/sim_config.go b/tests/simulation/sim/sim_config.go index 43c150303e..98d2ffb6d9 100644 --- a/tests/simulation/sim/sim_config.go +++ b/tests/simulation/sim/sim_config.go @@ -32,12 +32,42 @@ var ( // GetSimulatorFlags gets the values of all the available simulation flags func GetSimulatorFlags() { // config fields - flag.StringVar(&FlagGenesisFileValue, "Genesis", "", "custom simulation genesis file; cannot be used with params file") - flag.StringVar(&FlagParamsFileValue, "Params", "", "custom simulation params file which overrides any random params; cannot be used with genesis") - flag.StringVar(&FlagExportParamsPathValue, "ExportParamsPath", "", "custom file path to save the exported params JSON") - flag.IntVar(&FlagExportParamsHeightValue, "ExportParamsHeight", 0, "height to which export the randomly generated params") - flag.StringVar(&FlagExportStatePathValue, "ExportStatePath", "", "custom file path to save the exported app state JSON") - flag.StringVar(&FlagExportStatsPathValue, "ExportStatsPath", "", "custom file path to save the exported simulation statistics JSON") + flag.StringVar( + &FlagGenesisFileValue, + "Genesis", + "", + "custom simulation genesis file; cannot be used with params file", + ) + flag.StringVar( + &FlagParamsFileValue, + "Params", + "", + "custom simulation params file which overrides any random params; cannot be used with genesis", + ) + flag.StringVar( + &FlagExportParamsPathValue, + "ExportParamsPath", + "", + "custom file path to save the exported params JSON", + ) + flag.IntVar( + &FlagExportParamsHeightValue, + "ExportParamsHeight", + 0, + "height to which export the randomly generated params", + ) + flag.StringVar( + &FlagExportStatePathValue, + "ExportStatePath", + "", + "custom file path to save the exported app state JSON", + ) + flag.StringVar( + &FlagExportStatsPathValue, + "ExportStatsPath", + "", + "custom file path to save the exported simulation statistics JSON", + ) flag.Int64Var(&FlagSeedValue, "Seed", 42, "simulation random seed") flag.IntVar(&FlagInitialBlockHeightValue, "InitialBlockHeight", 1, "initial block to start the simulation") flag.IntVar(&FlagNumBlocksValue, "NumBlocks", 500, "number of new blocks to simulate from the initial block height") @@ -45,13 +75,23 @@ func GetSimulatorFlags() { flag.BoolVar(&FlagLeanValue, "Lean", false, "lean simulation log output") flag.BoolVar(&FlagCommitValue, "Commit", false, "have the simulation commit") flag.BoolVar(&FlagOnOperationValue, "SimulateEveryOperation", false, "run slow invariants every operation") - flag.BoolVar(&FlagAllInvariantsValue, "PrintAllInvariants", false, "print all invariants if a broken invariant is found") + flag.BoolVar( + &FlagAllInvariantsValue, + "PrintAllInvariants", + false, + "print all invariants if a broken invariant is found", + ) // simulation flags flag.BoolVar(&FlagEnabledValue, "Enabled", false, "enable the simulation") flag.BoolVar(&FlagVerboseValue, "Verbose", false, "verbose log output") flag.UintVar(&FlagPeriodValue, "Period", 0, "run slow invariants only once every period assertions") - flag.Int64Var(&FlagGenesisTimeValue, "GenesisTime", 0, "override genesis UNIX time instead of using a random UNIX time") + flag.Int64Var( + &FlagGenesisTimeValue, + "GenesisTime", + 0, + "override genesis UNIX time instead of using a random UNIX time", + ) } // NewConfigFromFlags creates a simulation from the retrieved values of the flags. diff --git a/tests/simulation/sim/sim_state.go b/tests/simulation/sim/sim_state.go index c4f884b9b4..2f314b6c78 100644 --- a/tests/simulation/sim/sim_state.go +++ b/tests/simulation/sim/sim_state.go @@ -33,7 +33,11 @@ const ( // 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.Codec, simManager *module.SimulationManager, genesisState map[string]json.RawMessage) simtypes.AppStateFn { +func AppStateFn( + cdc codec.Codec, + 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 FlagGenesisTimeValue == 0 { @@ -74,11 +78,27 @@ func AppStateFn(cdc codec.Codec, simManager *module.SimulationManager, genesisSt if err != nil { panic(err) } - appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams, genesisState) + appState, simAccs = AppStateRandomizedFn( + simManager, + r, + cdc, + accs, + genesisTimestamp, + appParams, + genesisState, + ) default: appParams := make(simtypes.AppParams) - appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams, genesisState) + appState, simAccs = AppStateRandomizedFn( + simManager, + r, + cdc, + accs, + genesisTimestamp, + appParams, + genesisState, + ) } rawState := make(map[string]json.RawMessage) @@ -223,7 +243,11 @@ 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) (tmtypes.GenesisDoc, []simtypes.Account, error) { +func AppStateFromGenesisFileFn( + r io.Reader, + cdc codec.JSONCodec, + genesisFile string, +) (tmtypes.GenesisDoc, []simtypes.Account, error) { bytes, err := os.ReadFile(genesisFile) if err != nil { panic(err) diff --git a/tests/simulation/sim/sim_utils.go b/tests/simulation/sim/sim_utils.go index a1e25fb8d7..b310d7cae2 100644 --- a/tests/simulation/sim/sim_utils.go +++ b/tests/simulation/sim/sim_utils.go @@ -9,12 +9,17 @@ import ( servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/zeta-chain/ethermint/app" evmante "github.com/zeta-chain/ethermint/app/ante" + zetaapp "github.com/zeta-chain/node/app" "github.com/zeta-chain/node/app/ante" ) -func NewSimApp(logger log.Logger, db dbm.DB, appOptions servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp)) (*zetaapp.App, error) { - +func NewSimApp( + logger log.Logger, + db dbm.DB, + appOptions servertypes.AppOptions, + baseAppOptions ...func(*baseapp.BaseApp), +) (*zetaapp.App, error) { encCdc := zetaapp.MakeEncodingConfig() // Set load latest version to false as we manually set it later. diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index ffb48f1f95..7d3d8305da 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -80,11 +80,23 @@ func TestAppStateDeterminism(t *testing.T) { } // For the same seed, the app hash produced at the end of each run should be the same for j := 0; j < numTimesToRunPerSeed; j++ { - db, dir, logger, _, err := cosmossimutils.SetupSimulation(config, SimDBBackend, SimDBName, simutils.FlagVerboseValue, simutils.FlagEnabledValue) + db, dir, logger, _, err := cosmossimutils.SetupSimulation( + config, + SimDBBackend, + SimDBName, + simutils.FlagVerboseValue, + simutils.FlagEnabledValue, + ) require.NoError(t, err) appOptions[flags.FlagHome] = dir - simApp, err := simutils.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := simutils.NewSimApp( + logger, + db, + appOptions, + interBlockCacheOpt(), + baseapp.SetChainID(SimAppChainID), + ) fmt.Printf( "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n", @@ -98,7 +110,11 @@ func TestAppStateDeterminism(t *testing.T) { t, os.Stdout, simApp.BaseApp, - simutils.AppStateFn(simApp.AppCodec(), simApp.SimulationManager(), simApp.ModuleBasics.DefaultGenesis(simApp.AppCodec())), + simutils.AppStateFn( + simApp.AppCodec(), + simApp.SimulationManager(), + simApp.ModuleBasics.DefaultGenesis(simApp.AppCodec()), + ), cosmossim.RandomAccounts, cosmossimutils.SimulationOperations(simApp, simApp.AppCodec(), config), blockedAddresses, @@ -114,8 +130,15 @@ func TestAppStateDeterminism(t *testing.T) { if j != 0 { require.Equal( - t, string(appHashList[0]), string(appHashList[j]), - "non-determinism in seed %d: %d/%d, attempt: %d/%d\n", config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed, + t, + string(appHashList[0]), + string(appHashList[j]), + "non-determinism in seed %d: %d/%d, attempt: %d/%d\n", + config.Seed, + i+1, + numSeeds, + j+1, + numTimesToRunPerSeed, ) } } @@ -132,7 +155,13 @@ func TestFullAppSimulation(t *testing.T) { config.BlockMaxGas = SimBlockMaxGas config.DBBackend = SimDBBackend - db, dir, logger, skip, err := cosmossimutils.SetupSimulation(config, SimDBBackend, SimDBName, simutils.FlagVerboseValue, simutils.FlagEnabledValue) + db, dir, logger, skip, err := cosmossimutils.SetupSimulation( + config, + SimDBBackend, + SimDBName, + simutils.FlagVerboseValue, + simutils.FlagEnabledValue, + ) if skip { t.Skip("skipping application simulation") } @@ -154,7 +183,11 @@ func TestFullAppSimulation(t *testing.T) { t, os.Stdout, simApp.BaseApp, - simutils.AppStateFn(simApp.AppCodec(), simApp.SimulationManager(), simApp.ModuleBasics.DefaultGenesis(simApp.AppCodec())), + simutils.AppStateFn( + simApp.AppCodec(), + simApp.SimulationManager(), + simApp.ModuleBasics.DefaultGenesis(simApp.AppCodec()), + ), cosmossim.RandomAccounts, cosmossimutils.SimulationOperations(simApp, simApp.AppCodec(), config), blockedAddresses, From cad3f4fc72a37da5773ba1ff529d08549a6b91d2 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 3 Oct 2024 10:50:11 +0530 Subject: [PATCH 11/59] add todos for BasicManager --- app/app.go | 88 ++++++++-------------- app/config.go | 2 +- app/encoding.go | 2 +- app/genesis.go | 21 ------ app/init_genesis.go | 66 ----------------- app/modules.go | 114 +++++++++++++++++++++++------ tests/simulation/sim/sim_config.go | 2 +- 7 files changed, 124 insertions(+), 171 deletions(-) delete mode 100644 app/genesis.go delete mode 100644 app/init_genesis.go diff --git a/app/app.go b/app/app.go index 3f8c295b31..86955375d7 100644 --- a/app/app.go +++ b/app/app.go @@ -1,6 +1,7 @@ package app import ( + "encoding/json" "io" "net/http" "os" @@ -177,64 +178,33 @@ func getGovProposalHandlers() []govclient.ProposalHandler { return govProposalHandlers } -var ( - ModuleBasics = module.NewBasicManager( - auth.AppModuleBasic{}, - genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), - bank.AppModuleBasic{}, - //capability.AppModuleBasic{}, - staking.AppModuleBasic{}, - distr.AppModuleBasic{}, - gov.NewAppModuleBasic(getGovProposalHandlers()), - params.AppModuleBasic{}, - crisis.AppModuleBasic{}, - slashing.AppModuleBasic{}, - //ibc.AppModuleBasic{}, - //ibctm.AppModuleBasic{}, - upgrade.AppModuleBasic{}, - evidence.AppModuleBasic{}, - //transfer.AppModuleBasic{}, - vesting.AppModuleBasic{}, - consensus.AppModuleBasic{}, - evm.AppModuleBasic{}, - feemarket.AppModuleBasic{}, - authoritymodule.AppModuleBasic{}, - lightclientmodule.AppModuleBasic{}, - crosschainmodule.AppModuleBasic{}, - //ibccrosschain.AppModuleBasic{}, - observermodule.AppModuleBasic{}, - fungiblemodule.AppModuleBasic{}, - emissionsmodule.AppModuleBasic{}, - groupmodule.AppModuleBasic{}, - authzmodule.AppModuleBasic{}, - ) - - // module account permissions - maccPerms = map[string][]string{ - authtypes.FeeCollectorName: nil, - distrtypes.ModuleName: nil, - stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, - stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, - govtypes.ModuleName: {authtypes.Burner}, - //ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - crosschaintypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - //ibccrosschaintypes.ModuleName: nil, - evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - fungibletypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - emissionstypes.ModuleName: nil, - emissionstypes.UndistributedObserverRewardsPool: nil, - emissionstypes.UndistributedTssRewardsPool: nil, - } +type GenesisState map[string]json.RawMessage + +// module account permissions +var maccPerms = map[string][]string{ + authtypes.FeeCollectorName: nil, + distrtypes.ModuleName: nil, + stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, + stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, + govtypes.ModuleName: {authtypes.Burner}, + //ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + crosschaintypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + //ibccrosschaintypes.ModuleName: nil, + evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + fungibletypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + emissionstypes.ModuleName: nil, + emissionstypes.UndistributedObserverRewardsPool: nil, + emissionstypes.UndistributedTssRewardsPool: nil, +} - // module accounts that are NOT allowed to receive tokens - blockedReceivingModAcc = map[string]bool{ - distrtypes.ModuleName: true, - authtypes.FeeCollectorName: true, - stakingtypes.BondedPoolName: true, - stakingtypes.NotBondedPoolName: true, - govtypes.ModuleName: true, - } -) +// module accounts that are NOT allowed to receive tokens +var blockedReceivingModAcc = map[string]bool{ + distrtypes.ModuleName: true, + authtypes.FeeCollectorName: true, + stakingtypes.BondedPoolName: true, + stakingtypes.NotBondedPoolName: true, + govtypes.ModuleName: true, +} var ( _ runtime.AppI = (*App)(nil) @@ -738,7 +708,7 @@ func New( authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), ) - app.ModuleBasics = newBasicManagerFromManager(app) + app.ModuleBasics = ModuleBasics // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the @@ -906,7 +876,7 @@ func (app *App) ModuleAccountAddrs() map[string]bool { return modAccAddrs } -// LegacyAmino returns SimApp's amino codec. +// LegacyAmino returns app'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/app/config.go b/app/config.go index 8f50ff8b7b..3aae668605 100644 --- a/app/config.go +++ b/app/config.go @@ -20,7 +20,7 @@ var ( FlagBlockSizeValue int FlagLeanValue bool FlagCommitValue bool - FlagOnOperationValue bool // TODO: Remove in favor of binary search for invariant violation + FlagOnOperationValue bool FlagAllInvariantsValue bool FlagEnabledValue bool diff --git a/app/encoding.go b/app/encoding.go index 2e8c728b0f..755b4ccbae 100644 --- a/app/encoding.go +++ b/app/encoding.go @@ -14,7 +14,6 @@ import ( evmenc "github.com/zeta-chain/ethermint/encoding" ethermint "github.com/zeta-chain/ethermint/types" evmtypes "github.com/zeta-chain/ethermint/x/evm/types" - authoritytypes "github.com/zeta-chain/node/x/authority/types" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" emissionstypes "github.com/zeta-chain/node/x/emissions/types" @@ -28,6 +27,7 @@ func MakeEncodingConfig() ethermint.EncodingConfig { encodingConfig := evmenc.MakeConfig(ModuleBasics) registry := encodingConfig.InterfaceRegistry + // TODO test if we need to register these interfaces again as MakeConfig already registers them cryptocodec.RegisterInterfaces(registry) authtypes.RegisterInterfaces(registry) authz.RegisterInterfaces(registry) diff --git a/app/genesis.go b/app/genesis.go deleted file mode 100644 index 5bf0c1da80..0000000000 --- a/app/genesis.go +++ /dev/null @@ -1,21 +0,0 @@ -package app - -import ( - "encoding/json" - - "github.com/cosmos/cosmos-sdk/codec" -) - -// The genesis state of the blockchain is represented here as a map of raw json -// messages key'd by a identifier string. -// The identifier is used to determine which module genesis information belongs -// to so it may be appropriately routed during init chain. -// Within this application default genesis information is retrieved from -// the ModuleBasicManager which populates json from each BasicModule -// object provided to it during init. -type GenesisState map[string]json.RawMessage - -// NewDefaultGenesisState generates the default state for the application. -func NewDefaultGenesisState(cdc codec.JSONCodec) GenesisState { - return ModuleBasics.DefaultGenesis(cdc) -} diff --git a/app/init_genesis.go b/app/init_genesis.go deleted file mode 100644 index b69972dbf8..0000000000 --- a/app/init_genesis.go +++ /dev/null @@ -1,66 +0,0 @@ -package app - -import ( - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - "github.com/cosmos/cosmos-sdk/x/authz" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" - crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/group" - paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" - slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - evmtypes "github.com/zeta-chain/ethermint/x/evm/types" - feemarkettypes "github.com/zeta-chain/ethermint/x/feemarket/types" - - authoritytypes "github.com/zeta-chain/node/x/authority/types" - crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" - emissionsModuleTypes "github.com/zeta-chain/node/x/emissions/types" - fungibleModuleTypes "github.com/zeta-chain/node/x/fungible/types" - lightclienttypes "github.com/zeta-chain/node/x/lightclient/types" - observertypes "github.com/zeta-chain/node/x/observer/types" -) - -// InitGenesisModuleList returns the module list for genesis initialization -// NOTE: Capability module must occur first so that it can initialize any capabilities -// TODO: enable back IBC -// all commented lines in this function are modules related to IBC -// https://github.com/zeta-chain/node/issues/2573 -func InitGenesisModuleList() []string { - return []string{ - //capabilitytypes.ModuleName, - authtypes.ModuleName, - banktypes.ModuleName, - distrtypes.ModuleName, - stakingtypes.ModuleName, - slashingtypes.ModuleName, - govtypes.ModuleName, - //ibcexported.ModuleName, - //ibctransfertypes.ModuleName, - evmtypes.ModuleName, - feemarkettypes.ModuleName, - paramstypes.ModuleName, - group.ModuleName, - genutiltypes.ModuleName, - upgradetypes.ModuleName, - evidencetypes.ModuleName, - vestingtypes.ModuleName, - observertypes.ModuleName, - crosschaintypes.ModuleName, - //ibccrosschaintypes.ModuleName, - fungibleModuleTypes.ModuleName, - emissionsModuleTypes.ModuleName, - authz.ModuleName, - authoritytypes.ModuleName, - lightclienttypes.ModuleName, - consensusparamtypes.ModuleName, - // NOTE: crisis module must go at the end to check for invariants on each module - crisistypes.ModuleName, - } -} diff --git a/app/modules.go b/app/modules.go index c94872305b..b041cc0d1a 100644 --- a/app/modules.go +++ b/app/modules.go @@ -1,59 +1,129 @@ package app import ( - "fmt" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + "github.com/cosmos/cosmos-sdk/x/authz" authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" "github.com/cosmos/cosmos-sdk/x/bank" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/consensus" + consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" + "github.com/cosmos/cosmos-sdk/x/crisis" + crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" distr "github.com/cosmos/cosmos-sdk/x/distribution" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/evidence" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/cosmos/cosmos-sdk/x/gov" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/group" groupmodule "github.com/cosmos/cosmos-sdk/x/group/module" "github.com/cosmos/cosmos-sdk/x/params" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/slashing" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/upgrade" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/zeta-chain/ethermint/x/evm" evmtypes "github.com/zeta-chain/ethermint/x/evm/types" + "github.com/zeta-chain/ethermint/x/feemarket" + feemarkettypes "github.com/zeta-chain/ethermint/x/feemarket/types" + authoritymodule "github.com/zeta-chain/node/x/authority" + authoritytypes "github.com/zeta-chain/node/x/authority/types" + crosschainmodule "github.com/zeta-chain/node/x/crosschain" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" + emissionsmodule "github.com/zeta-chain/node/x/emissions" + emissionsModuleTypes "github.com/zeta-chain/node/x/emissions/types" + fungiblemodule "github.com/zeta-chain/node/x/fungible" + fungibleModuleTypes "github.com/zeta-chain/node/x/fungible/types" + lightclientmodule "github.com/zeta-chain/node/x/lightclient" + lightclienttypes "github.com/zeta-chain/node/x/lightclient/types" + observermodule "github.com/zeta-chain/node/x/observer" + observertypes "github.com/zeta-chain/node/x/observer/types" ) // ModuleBasics defines the module BasicManager that is in charge of setting up basic, // non-dependant module elements, such as codec registration // and genesis verification. -func newBasicManagerFromManager(app *App) module.BasicManager { - moduleBasics := make([]module.AppModuleBasic, 0) - for _, m := range app.mm.Modules { - m, ok := m.(module.AppModuleBasic) - if !ok { - fmt.Printf("module %s is not an instance of module.AppModuleBasic\n", m) - continue - } - if m.Name() == govtypes.ModuleName { - m = gov.NewAppModuleBasic(getGovProposalHandlers()) - } - if m.Name() == genutiltypes.ModuleName { - m = genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator) - } +// TODO: Use app.mm to create the basic manager instead +var ModuleBasics = module.NewBasicManager( + auth.AppModuleBasic{}, + genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + bank.AppModuleBasic{}, + //capability.AppModuleBasic{}, + staking.AppModuleBasic{}, + distr.AppModuleBasic{}, + gov.NewAppModuleBasic(getGovProposalHandlers()), + params.AppModuleBasic{}, + crisis.AppModuleBasic{}, + slashing.AppModuleBasic{}, + //ibc.AppModuleBasic{}, + //ibctm.AppModuleBasic{}, + upgrade.AppModuleBasic{}, + evidence.AppModuleBasic{}, + //transfer.AppModuleBasic{}, + vesting.AppModuleBasic{}, + consensus.AppModuleBasic{}, + evm.AppModuleBasic{}, + feemarket.AppModuleBasic{}, + authoritymodule.AppModuleBasic{}, + lightclientmodule.AppModuleBasic{}, + crosschainmodule.AppModuleBasic{}, + //ibccrosschain.AppModuleBasic{}, + observermodule.AppModuleBasic{}, + fungiblemodule.AppModuleBasic{}, + emissionsmodule.AppModuleBasic{}, + groupmodule.AppModuleBasic{}, + authzmodule.AppModuleBasic{}, +) - moduleBasics = append(moduleBasics, m) +// InitGenesisModuleList returns the module list for genesis initialization +// NOTE: Capability module must occur first so that it can initialize any capabilities +// TODO: enable back IBC +// all commented lines in this function are modules related to IBC +// https://github.com/zeta-chain/node/issues/2573 +func InitGenesisModuleList() []string { + return []string{ + //capabilitytypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + distrtypes.ModuleName, + stakingtypes.ModuleName, + slashingtypes.ModuleName, + govtypes.ModuleName, + //ibcexported.ModuleName, + //ibctransfertypes.ModuleName, + evmtypes.ModuleName, + feemarkettypes.ModuleName, + paramstypes.ModuleName, + group.ModuleName, + genutiltypes.ModuleName, + upgradetypes.ModuleName, + evidencetypes.ModuleName, + vestingtypes.ModuleName, + observertypes.ModuleName, + crosschaintypes.ModuleName, + //ibccrosschaintypes.ModuleName, + fungibleModuleTypes.ModuleName, + emissionsModuleTypes.ModuleName, + authz.ModuleName, + authoritytypes.ModuleName, + lightclienttypes.ModuleName, + consensusparamtypes.ModuleName, + // NOTE: crisis module must go at the end to check for invariants on each module + crisistypes.ModuleName, } - basicManager := module.NewBasicManager(moduleBasics...) - //basicManager.RegisterLegacyAminoCodec(app.cdc) - basicManager.RegisterInterfaces(app.interfaceRegistry) - - return basicManager } func simulationModules( diff --git a/tests/simulation/sim/sim_config.go b/tests/simulation/sim/sim_config.go index 98d2ffb6d9..915a77dd40 100644 --- a/tests/simulation/sim/sim_config.go +++ b/tests/simulation/sim/sim_config.go @@ -20,7 +20,7 @@ var ( FlagBlockSizeValue int FlagLeanValue bool FlagCommitValue bool - FlagOnOperationValue bool // TODO: Remove in favor of binary search for invariant violation + FlagOnOperationValue bool FlagAllInvariantsValue bool FlagEnabledValue bool From c07d5194747909defbdab1e2c98ea48a7d858e6b Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 3 Oct 2024 12:32:28 +0530 Subject: [PATCH 12/59] add todos for BasicManager --- app/encoding.go | 1 + app/modules.go | 16 +++++++++------- sims.mk | 27 ++++++++++++++++----------- tests/simulation/sim/sim_config.go | 15 +++++++++++---- tests/simulation/sim_test.go | 4 ++++ 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/app/encoding.go b/app/encoding.go index 755b4ccbae..44748dacee 100644 --- a/app/encoding.go +++ b/app/encoding.go @@ -14,6 +14,7 @@ import ( evmenc "github.com/zeta-chain/ethermint/encoding" ethermint "github.com/zeta-chain/ethermint/types" evmtypes "github.com/zeta-chain/ethermint/x/evm/types" + authoritytypes "github.com/zeta-chain/node/x/authority/types" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" emissionstypes "github.com/zeta-chain/node/x/emissions/types" diff --git a/app/modules.go b/app/modules.go index b041cc0d1a..038b3766aa 100644 --- a/app/modules.go +++ b/app/modules.go @@ -38,6 +38,7 @@ import ( evmtypes "github.com/zeta-chain/ethermint/x/evm/types" "github.com/zeta-chain/ethermint/x/feemarket" feemarkettypes "github.com/zeta-chain/ethermint/x/feemarket/types" + authoritymodule "github.com/zeta-chain/node/x/authority" authoritytypes "github.com/zeta-chain/node/x/authority/types" crosschainmodule "github.com/zeta-chain/node/x/crosschain" @@ -126,6 +127,7 @@ func InitGenesisModuleList() []string { } } +// simulationModules returns a list of modules to include in the simulation func simulationModules( app *App, appCodec codec.Codec, @@ -139,13 +141,13 @@ func simulationModules( app.GetSubspace(authtypes.ModuleName), ), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), - gov.NewAppModule( - appCodec, - &app.GovKeeper, - app.AccountKeeper, - app.BankKeeper, - app.GetSubspace(govtypes.ModuleName), - ), + //gov.NewAppModule( + // appCodec, + // &app.GovKeeper, + // app.AccountKeeper, + // app.BankKeeper, + // app.GetSubspace(govtypes.ModuleName), + //), staking.NewAppModule( appCodec, app.StakingKeeper, diff --git a/sims.mk b/sims.mk index db4b4d7a5c..ea81e40807 100644 --- a/sims.mk +++ b/sims.mk @@ -10,27 +10,32 @@ SIMAPP = ./tests/simulation # Run sim is a cosmos tool which helps us to run multiple simulations in parallel. runsim: $(BINDIR)/runsim $(BINDIR)/runsim: - @echo "Installing runsim..." - @(cd /tmp && go install github.com/cosmos/tools/cmd/runsim@v1.0.0) + @echo 'Installing runsim...' + @TEMP_DIR=$$(mktemp -d) && \ + cd $$TEMP_DIR && \ + go install github.com/cosmos/tools/cmd/runsim@v1.0.0 && \ + rm -rf $$TEMP_DIR || (echo 'Failed to install runsim' && exit 1) + @echo 'runsim installed successfully' -test-sim-nondeterminism: - @echo "Running non-determinism test..." - @go test -mod=readonly $(SIMAPP) -run TestAppStateDeterminism -Enabled=true \ - -NumBlocks=10 -BlockSize=20 -Commit=true -Period=0 -v -timeout 24h +define run-sim-test + @echo "Running $(1)..." + @go test -mod=readonly $(SIMAPP) -run $(2) -Enabled=true \ + -NumBlocks=$(3) -BlockSize=$(4) -Commit=true -Period=0 -v -timeout $(5) +endef +test-sim-nondeterminism: + $(call run-sim-test,"non-determinism test",TestAppStateDeterminism,100,200,2h) test-sim-fullappsimulation: - @echo "Running TestFullAppSimulation." - @go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation -Enabled=true \ - -NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h + $(call run-sim-test,"TestFullAppSimulation",TestFullAppSimulation,100,200,2h) test-sim-multi-seed-long: runsim - @echo "Running long multi-seed application simulation. This may take awhile!" + @echo "Running long multi-seed application simulation." @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestFullAppSimulation test-sim-multi-seed-short: runsim - @echo "Running short multi-seed application simulation. This may take awhile!" + @echo "Running short multi-seed application simulation." @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation diff --git a/tests/simulation/sim/sim_config.go b/tests/simulation/sim/sim_config.go index 915a77dd40..c306f47f54 100644 --- a/tests/simulation/sim/sim_config.go +++ b/tests/simulation/sim/sim_config.go @@ -6,6 +6,13 @@ import ( "github.com/cosmos/cosmos-sdk/types/simulation" ) +const ( + defaultSeed = 42 + defaultNumBlocks = 500 + defaultInitialHeight = 1 + defaultBlockSize = 200 +) + // List of available flags for the simulator var ( FlagGenesisFileValue string @@ -68,10 +75,10 @@ func GetSimulatorFlags() { "", "custom file path to save the exported simulation statistics JSON", ) - flag.Int64Var(&FlagSeedValue, "Seed", 42, "simulation random seed") - flag.IntVar(&FlagInitialBlockHeightValue, "InitialBlockHeight", 1, "initial block to start the simulation") - flag.IntVar(&FlagNumBlocksValue, "NumBlocks", 500, "number of new blocks to simulate from the initial block height") - flag.IntVar(&FlagBlockSizeValue, "BlockSize", 200, "operations per block") + flag.Int64Var(&FlagSeedValue, "Seed", defaultSeed, "simulation random seed") + flag.IntVar(&FlagInitialBlockHeightValue, "InitialBlockHeight", defaultInitialHeight, "initial block to start the simulation") + flag.IntVar(&FlagNumBlocksValue, "NumBlocks", defaultNumBlocks, "number of new blocks to simulate from the initial block height") + flag.IntVar(&FlagBlockSizeValue, "BlockSize", defaultBlockSize, "operations per block") flag.BoolVar(&FlagLeanValue, "Lean", false, "lean simulation log output") flag.BoolVar(&FlagCommitValue, "Commit", false, "have the simulation commit") flag.BoolVar(&FlagOnOperationValue, "SimulateEveryOperation", false, "run slow invariants every operation") diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 7d3d8305da..3b313338f4 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -128,6 +128,10 @@ func TestAppStateDeterminism(t *testing.T) { appHash := simApp.LastCommitID().Hash appHashList[j] = appHash + // Clean up resources + require.NoError(t, db.Close()) + require.NoError(t, os.RemoveAll(dir)) + if j != 0 { require.Equal( t, From 4f3ebbe3c81a6bd7a01de4eb2c74f5d2344f571f Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 3 Oct 2024 12:54:20 +0530 Subject: [PATCH 13/59] add cleanup for TestFullAppSimulation --- app/config.go | 2 +- tests/simulation/sim_test.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/config.go b/app/config.go index 3aae668605..8f50ff8b7b 100644 --- a/app/config.go +++ b/app/config.go @@ -20,7 +20,7 @@ var ( FlagBlockSizeValue int FlagLeanValue bool FlagCommitValue bool - FlagOnOperationValue bool + FlagOnOperationValue bool // TODO: Remove in favor of binary search for invariant violation FlagAllInvariantsValue bool FlagEnabledValue bool diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 3b313338f4..3fe882fe79 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -209,4 +209,8 @@ func TestFullAppSimulation(t *testing.T) { } simutils.PrintStats(db) + + // Clean up resources + require.NoError(t, db.Close()) + require.NoError(t, os.RemoveAll(dir)) } From 56b469858b6ba01939cea9cc5c2b2f05dd56d904 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 3 Oct 2024 13:17:34 +0530 Subject: [PATCH 14/59] register legacy router --- app/app.go | 4 ++++ app/modules.go | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/app.go b/app/app.go index 86955375d7..6e0a86b01b 100644 --- a/app/app.go +++ b/app/app.go @@ -607,6 +607,7 @@ func New( govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler). AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) + govConfig := govtypes.DefaultConfig() govKeeper := govkeeper.NewKeeper( appCodec, @@ -618,11 +619,14 @@ func New( govConfig, authAddr, ) + app.GovKeeper = *govKeeper.SetHooks( govtypes.NewMultiGovHooks( // register governance hooks ), ) + // Set legacy router for backwards compatibility with gov v1beta1 + app.GovKeeper.SetLegacyRouter(govRouter) // Create evidence Keeper for to register the IBC light client misbehaviour evidence route evidenceKeeper := evidencekeeper.NewKeeper( diff --git a/app/modules.go b/app/modules.go index 038b3766aa..3324680902 100644 --- a/app/modules.go +++ b/app/modules.go @@ -141,13 +141,13 @@ func simulationModules( app.GetSubspace(authtypes.ModuleName), ), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), - //gov.NewAppModule( - // appCodec, - // &app.GovKeeper, - // app.AccountKeeper, - // app.BankKeeper, - // app.GetSubspace(govtypes.ModuleName), - //), + gov.NewAppModule( + appCodec, + &app.GovKeeper, + app.AccountKeeper, + app.BankKeeper, + app.GetSubspace(govtypes.ModuleName), + ), staking.NewAppModule( appCodec, app.StakingKeeper, From c1db4cf4cedc9086d3e3c67a820aea587149f513 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 3 Oct 2024 20:46:25 +0530 Subject: [PATCH 15/59] added a doc for simulation testing --- docs/development/SIMULATION_TESTING.md | 13 +++++++++++++ readme.md | 1 + 2 files changed, 14 insertions(+) create mode 100644 docs/development/SIMULATION_TESTING.md diff --git a/docs/development/SIMULATION_TESTING.md b/docs/development/SIMULATION_TESTING.md new file mode 100644 index 0000000000..332f6710a3 --- /dev/null +++ b/docs/development/SIMULATION_TESTING.md @@ -0,0 +1,13 @@ +# Zetachain simulation testing + + +## Running the simulation tests + +The simulation tests can be run with the following command: +```bash + +make -f sims.mk test-sim-nondeterminism +make -f sims.mk test-sim-fullappsimulation +make -f sims.mk test-sim-multi-seed-long +make -f sims.mk test-sim-multi-seed-short +``` \ No newline at end of file diff --git a/readme.md b/readme.md index 61f04f632f..89a5befb3a 100644 --- a/readme.md +++ b/readme.md @@ -73,6 +73,7 @@ Find below further documentation for development and running your own ZetaChain - [Run the E2E tests and interact with the localnet](docs/development/LOCAL_TESTING.md) - [Make a new ZetaChain release](docs/development/RELEASES.md) - [Deploy your own ZetaChain or Bitcoin node](docs/development/DEPLOY_NODES.md) +- [Run the simulation tests](docs/development/SIMULATION_TESTING.md) ## Community From d98add5809b3f31a3ea9e42713e41d4abac589d8 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 3 Oct 2024 20:52:27 +0530 Subject: [PATCH 16/59] undo db close for multi threaded test --- tests/simulation/sim_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 3fe882fe79..3b313338f4 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -209,8 +209,4 @@ func TestFullAppSimulation(t *testing.T) { } simutils.PrintStats(db) - - // Clean up resources - require.NoError(t, db.Close()) - require.NoError(t, os.RemoveAll(dir)) } From bff41210668ed41ce0bb8c5c4600fac5d39ac8cb Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 14 Oct 2024 10:20:16 +0530 Subject: [PATCH 17/59] add description for tests --- Makefile | 55 ++++++++++++++++++++++++++ app/encoding.go | 1 + changelog.md | 2 +- docs/development/SIMULATION_TESTING.md | 36 ++++++++++++++--- sims.mk | 48 ---------------------- tests/simulation/sim/sim_config.go | 14 ++++++- tests/simulation/sim_test.go | 13 +++--- 7 files changed, 106 insertions(+), 63 deletions(-) delete mode 100644 sims.mk diff --git a/Makefile b/Makefile index b3fbf4009a..bd7b0df002 100644 --- a/Makefile +++ b/Makefile @@ -345,6 +345,61 @@ start-upgrade-import-mainnet-test: zetanode-upgrade export UPGRADE_HEIGHT=225 && \ cd contrib/localnet/ && ./scripts/import-data.sh mainnet && $(DOCKER_COMPOSE) --profile upgrade -f docker-compose.yml -f docker-compose-upgrade.yml up -d + +############################################################################### +### Simulation Tests ### +############################################################################### + +BINDIR ?= $(GOPATH)/bin +SIMAPP = ./tests/simulation + + +# Run sim is a cosmos tool which helps us to run multiple simulations in parallel. +runsim: $(BINDIR)/runsim +$(BINDIR)/runsim: + @echo 'Installing runsim...' + @TEMP_DIR=$$(mktemp -d) && \ + cd $$TEMP_DIR && \ + go install github.com/cosmos/tools/cmd/runsim@v1.0.0 && \ + rm -rf $$TEMP_DIR || (echo 'Failed to install runsim' && exit 1) + @echo 'runsim installed successfully' + + +# Configuaration parameters for simulation tests +# NumBlocks: Number of blocks to simulate +# BlockSize: Number of transactions in a block +# Commit: Whether to commit the block or not +# Period: Invariant check period +# Timeout: Timeout for the simulation test +define run-sim-test + @echo "Running $(1)..." + @go test -mod=readonly $(SIMAPP) -run $(2) -Enabled=true \ + -NumBlocks=$(3) -BlockSize=$(4) -Commit=true -Period=0 -v -timeout $(5) +endef + +test-sim-nondeterminism: + $(call run-sim-test,"non-determinism test",TestAppStateDeterminism,100,200,2h) + +test-sim-fullappsimulation: + $(call run-sim-test,"TestFullAppSimulation",TestFullAppSimulation,100,200,2h) + +test-sim-multi-seed-long: runsim + @echo "Running long multi-seed application simulation." + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestFullAppSimulation + +test-sim-multi-seed-short: runsim + @echo "Running short multi-seed application simulation." + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation + + + +.PHONY: \ +test-sim-nondeterminism \ +test-sim-fullappsimulation \ +test-sim-multi-seed-long \ +test-sim-multi-seed-short + + ############################################################################### ### GoReleaser ### ############################################################################### diff --git a/app/encoding.go b/app/encoding.go index 44748dacee..674887f670 100644 --- a/app/encoding.go +++ b/app/encoding.go @@ -29,6 +29,7 @@ func MakeEncodingConfig() ethermint.EncodingConfig { registry := encodingConfig.InterfaceRegistry // TODO test if we need to register these interfaces again as MakeConfig already registers them + // https://github.com/zeta-chain/node/issues/3003 cryptocodec.RegisterInterfaces(registry) authtypes.RegisterInterfaces(registry) authz.RegisterInterfaces(registry) diff --git a/changelog.md b/changelog.md index 6069bac909..b76c8bba4d 100644 --- a/changelog.md +++ b/changelog.md @@ -36,7 +36,7 @@ * [2874](https://github.com/zeta-chain/node/pull/2874) - add support for multiple runs for precompile tests * [2895](https://github.com/zeta-chain/node/pull/2895) - add e2e test for bitcoin deposit and call * [2894](https://github.com/zeta-chain/node/pull/2894) - increase gas limit for TSS vote tx -* [2947](https://github.com/zeta-chain/node/pull/2947/) - add simulation tests +* [2947](https://github.com/zeta-chain/node/pull/2947/) - initialize simulation tests ### Fixes diff --git a/docs/development/SIMULATION_TESTING.md b/docs/development/SIMULATION_TESTING.md index 332f6710a3..c14e2e2713 100644 --- a/docs/development/SIMULATION_TESTING.md +++ b/docs/development/SIMULATION_TESTING.md @@ -1,13 +1,37 @@ # Zetachain simulation testing -## Running the simulation tests -The simulation tests can be run with the following command: +## Overview +The blockchain simulation tests how the blockchain application would behave under real life circumstances by generating +and sending randomized messages.The goal of this is to detect and debug failures that could halt a live chain,by providing +logs and statistics about the operations run by the simulator as well as exporting the latest application state. + + +## Simulation tests + +### Nondeterminism test +Nondeterminism test runs a full application simulation , and produces multiple blocks as per the config +It checks the determinism of the application by comparing the apphash at the end of each run to other runs +The test certifies that , for the same set of operations ( irrespective of what the operations are ), we would reach the same final state if the initial state is the same +```bash +make test-sim-nondeterminism +``` +### Full application simulation test +Full application runs a full app simulation test with the provided configuration. +At the end of the run it tries to export the genesis state to make sure the export works. ```bash +make test-sim-full-app +``` -make -f sims.mk test-sim-nondeterminism -make -f sims.mk test-sim-fullappsimulation -make -f sims.mk test-sim-multi-seed-long -make -f sims.mk test-sim-multi-seed-short +### Multi seed long test +Multi seed long test runs a full application simulation with multiple seeds and multiple blocks.This runs the test for a longer duration compared to the multi seed short test +```bash +make test-sim-multi-seed-long +``` + +### Multi seed short test +Multi seed short test runs a full application simulation with multiple seeds and multiple blocks. This runs the test for a longer duration compared to the multi seed long test +```bash +make test-sim-multi-seed-short ``` \ No newline at end of file diff --git a/sims.mk b/sims.mk deleted file mode 100644 index ea81e40807..0000000000 --- a/sims.mk +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/make -f - -######################################## -### Simulations - -BINDIR ?= $(GOPATH)/bin -SIMAPP = ./tests/simulation - - -# Run sim is a cosmos tool which helps us to run multiple simulations in parallel. -runsim: $(BINDIR)/runsim -$(BINDIR)/runsim: - @echo 'Installing runsim...' - @TEMP_DIR=$$(mktemp -d) && \ - cd $$TEMP_DIR && \ - go install github.com/cosmos/tools/cmd/runsim@v1.0.0 && \ - rm -rf $$TEMP_DIR || (echo 'Failed to install runsim' && exit 1) - @echo 'runsim installed successfully' - - -define run-sim-test - @echo "Running $(1)..." - @go test -mod=readonly $(SIMAPP) -run $(2) -Enabled=true \ - -NumBlocks=$(3) -BlockSize=$(4) -Commit=true -Period=0 -v -timeout $(5) -endef - -test-sim-nondeterminism: - $(call run-sim-test,"non-determinism test",TestAppStateDeterminism,100,200,2h) - -test-sim-fullappsimulation: - $(call run-sim-test,"TestFullAppSimulation",TestFullAppSimulation,100,200,2h) - -test-sim-multi-seed-long: runsim - @echo "Running long multi-seed application simulation." - @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestFullAppSimulation - -test-sim-multi-seed-short: runsim - @echo "Running short multi-seed application simulation." - @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation - - - -.PHONY: \ -test-sim-nondeterminism \ -test-sim-fullappsimulation \ -test-sim-multi-seed-long \ -test-sim-multi-seed-short - diff --git a/tests/simulation/sim/sim_config.go b/tests/simulation/sim/sim_config.go index c306f47f54..8a6c281db8 100644 --- a/tests/simulation/sim/sim_config.go +++ b/tests/simulation/sim/sim_config.go @@ -76,8 +76,18 @@ func GetSimulatorFlags() { "custom file path to save the exported simulation statistics JSON", ) flag.Int64Var(&FlagSeedValue, "Seed", defaultSeed, "simulation random seed") - flag.IntVar(&FlagInitialBlockHeightValue, "InitialBlockHeight", defaultInitialHeight, "initial block to start the simulation") - flag.IntVar(&FlagNumBlocksValue, "NumBlocks", defaultNumBlocks, "number of new blocks to simulate from the initial block height") + flag.IntVar( + &FlagInitialBlockHeightValue, + "InitialBlockHeight", + defaultInitialHeight, + "initial block to start the simulation", + ) + flag.IntVar( + &FlagNumBlocksValue, + "NumBlocks", + defaultNumBlocks, + "number of new blocks to simulate from the initial block height", + ) flag.IntVar(&FlagBlockSizeValue, "BlockSize", defaultBlockSize, "operations per block") flag.BoolVar(&FlagLeanValue, "Lean", false, "lean simulation log output") flag.BoolVar(&FlagCommitValue, "Commit", false, "have the simulation commit") diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 3b313338f4..385767aeac 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -2,7 +2,6 @@ package simulation_test import ( "encoding/json" - "fmt" "math/rand" "os" "testing" @@ -30,8 +29,10 @@ func init() { const ( SimAppChainID = "simulation_777-1" SimBlockMaxGas = 815000000 - SimDBBackend = "goleveldb" - SimDBName = "simulation" + //github.com/zeta-chain/node/issues/3004 + // TODO : Support pebbleDB for simulation tests + SimDBBackend = "goleveldb" + SimDBName = "simulation" ) // interBlockCacheOpt returns a BaseApp option function that sets the persistent @@ -43,7 +44,7 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { // TestAppStateDeterminism runs a full application simulation , and produces multiple blocks as per the config // It checks the determinism of the application by comparing the apphash at the end of each run to other runs // The following test certifies that , for the same set of operations ( irrespective of what the operations are ) , -// we would reach the same final state if the initital state is the same +// we would reach the same final state if the initial state is the same func TestAppStateDeterminism(t *testing.T) { if !simutils.FlagEnabledValue { t.Skip("skipping application simulation") @@ -72,7 +73,7 @@ func TestAppStateDeterminism(t *testing.T) { appOptions := make(cosmossimutils.AppOptionsMap, 0) appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue - fmt.Println("Running tests for numSeeds: ", numSeeds, " numTimesToRunPerSeed: ", numTimesToRunPerSeed) + t.Log("Running tests for numSeeds: ", numSeeds, " numTimesToRunPerSeed: ", numTimesToRunPerSeed) for i := 0; i < numSeeds; i++ { if config.Seed == cosmossimcli.DefaultSeedValue { @@ -98,7 +99,7 @@ func TestAppStateDeterminism(t *testing.T) { baseapp.SetChainID(SimAppChainID), ) - fmt.Printf( + t.Logf( "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n", config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed, ) From 74b0ad7c2e62aa94826cebaaf1421e83523f15fb Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 15 Oct 2024 11:57:37 +0530 Subject: [PATCH 18/59] remove go module from simulation tests --- app/app.go | 2 +- app/modules.go | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/app.go b/app/app.go index 6e0a86b01b..619b33fd0b 100644 --- a/app/app.go +++ b/app/app.go @@ -626,7 +626,7 @@ func New( ), ) // Set legacy router for backwards compatibility with gov v1beta1 - app.GovKeeper.SetLegacyRouter(govRouter) + // app.GovKeeper.SetLegacyRouter(govRouter) // Create evidence Keeper for to register the IBC light client misbehaviour evidence route evidenceKeeper := evidencekeeper.NewKeeper( diff --git a/app/modules.go b/app/modules.go index 3324680902..c9800a2f61 100644 --- a/app/modules.go +++ b/app/modules.go @@ -141,13 +141,15 @@ func simulationModules( app.GetSubspace(authtypes.ModuleName), ), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), - gov.NewAppModule( - appCodec, - &app.GovKeeper, - app.AccountKeeper, - app.BankKeeper, - app.GetSubspace(govtypes.ModuleName), - ), + // Todo : Enable gov module simulation + // https://github.com/zeta-chain/node/issues/3007 + //gov.NewAppModule( + // appCodec, + // &app.GovKeeper, + // app.AccountKeeper, + // app.BankKeeper, + // app.GetSubspace(govtypes.ModuleName), + //), staking.NewAppModule( appCodec, app.StakingKeeper, From f8c095d8b9820bc8de07ac0e29c30dce0f991d8c Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 18 Oct 2024 12:34:53 -0400 Subject: [PATCH 19/59] make basicsmanager private --- app/app.go | 11 ++++++++--- app/modules.go | 2 +- tests/simulation/sim_test.go | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/app.go b/app/app.go index 619b33fd0b..703a970cba 100644 --- a/app/app.go +++ b/app/app.go @@ -229,7 +229,7 @@ type App struct { mm *module.Manager sm *module.SimulationManager - ModuleBasics module.BasicManager + mb module.BasicManager configurator module.Configurator // sdk keepers @@ -712,7 +712,7 @@ func New( authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), ) - app.ModuleBasics = ModuleBasics + app.mb = ModuleBasics // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the @@ -943,7 +943,7 @@ func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // Register legacy and grpc-gateway routes for all modules. - app.ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + app.mb.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // register app's OpenAPI routes. if apiConfig.Swagger { @@ -1035,6 +1035,11 @@ func (app *App) SimulationManager() *module.SimulationManager { return app.sm } +func (app *App) BasicManager() module.BasicManager { + return app.mb + +} + func (app *App) BlockedAddrs() map[string]bool { blockList := make(map[string]bool) diff --git a/app/modules.go b/app/modules.go index c9800a2f61..6f164a9409 100644 --- a/app/modules.go +++ b/app/modules.go @@ -56,7 +56,7 @@ import ( // ModuleBasics defines the module BasicManager that is in charge of setting up basic, // non-dependant module elements, such as codec registration // and genesis verification. - +// https://github.com/zeta-chain/node/issues/3021 // TODO: Use app.mm to create the basic manager instead var ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 385767aeac..957e92081a 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -114,7 +114,7 @@ func TestAppStateDeterminism(t *testing.T) { simutils.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), - simApp.ModuleBasics.DefaultGenesis(simApp.AppCodec()), + simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), ), cosmossim.RandomAccounts, cosmossimutils.SimulationOperations(simApp, simApp.AppCodec(), config), @@ -191,7 +191,7 @@ func TestFullAppSimulation(t *testing.T) { simutils.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), - simApp.ModuleBasics.DefaultGenesis(simApp.AppCodec()), + simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), ), cosmossim.RandomAccounts, cosmossimutils.SimulationOperations(simApp, simApp.AppCodec(), config), From b49be6b4e376691da1883e9926ede4afe7dd4b08 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 22 Oct 2024 08:46:45 -0400 Subject: [PATCH 20/59] Update Makefile Co-authored-by: Francisco de Borja Aranda Castillejo --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bd7b0df002..f4aa4f5e47 100644 --- a/Makefile +++ b/Makefile @@ -365,7 +365,7 @@ $(BINDIR)/runsim: @echo 'runsim installed successfully' -# Configuaration parameters for simulation tests +# Configuration parameters for simulation tests # NumBlocks: Number of blocks to simulate # BlockSize: Number of transactions in a block # Commit: Whether to commit the block or not From cf4cb457293fe9d239303db98ca7bf46c1ae5848 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 22 Oct 2024 08:46:57 -0400 Subject: [PATCH 21/59] Update changelog.md Co-authored-by: Francisco de Borja Aranda Castillejo --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index b76c8bba4d..ecd222d1ef 100644 --- a/changelog.md +++ b/changelog.md @@ -36,7 +36,7 @@ * [2874](https://github.com/zeta-chain/node/pull/2874) - add support for multiple runs for precompile tests * [2895](https://github.com/zeta-chain/node/pull/2895) - add e2e test for bitcoin deposit and call * [2894](https://github.com/zeta-chain/node/pull/2894) - increase gas limit for TSS vote tx -* [2947](https://github.com/zeta-chain/node/pull/2947/) - initialize simulation tests +* [2947](https://github.com/zeta-chain/node/pull/2947) - initialize simulation tests ### Fixes From d5ae57c68df2a2adade97b8dce3ad98e2bcaad32 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 22 Oct 2024 08:58:57 -0400 Subject: [PATCH 22/59] format simulation.md --- app/app.go | 1 - docs/development/SIMULATION_TESTING.md | 3 --- 2 files changed, 4 deletions(-) diff --git a/app/app.go b/app/app.go index 703a970cba..971e6ce710 100644 --- a/app/app.go +++ b/app/app.go @@ -1037,7 +1037,6 @@ func (app *App) SimulationManager() *module.SimulationManager { func (app *App) BasicManager() module.BasicManager { return app.mb - } func (app *App) BlockedAddrs() map[string]bool { diff --git a/docs/development/SIMULATION_TESTING.md b/docs/development/SIMULATION_TESTING.md index c14e2e2713..1f5232911a 100644 --- a/docs/development/SIMULATION_TESTING.md +++ b/docs/development/SIMULATION_TESTING.md @@ -1,7 +1,4 @@ # Zetachain simulation testing - - - ## Overview The blockchain simulation tests how the blockchain application would behave under real life circumstances by generating and sending randomized messages.The goal of this is to detect and debug failures that could halt a live chain,by providing From e1cc91f9645da6ba5080f1399f7c623492542161 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 22 Oct 2024 12:57:20 -0400 Subject: [PATCH 23/59] add test for import export --- Makefile | 8 +- app/app.go | 8 ++ tests/simulation/sim/sim_utils.go | 33 +++++ tests/simulation/sim/sim_utils_cosmos.go | 114 ++++++++++++++++ tests/simulation/sim_test.go | 165 ++++++++++++++++++++++- 5 files changed, 325 insertions(+), 3 deletions(-) create mode 100644 tests/simulation/sim/sim_utils_cosmos.go diff --git a/Makefile b/Makefile index f1e56c2953..3ac53b338e 100644 --- a/Makefile +++ b/Makefile @@ -387,7 +387,7 @@ define run-sim-test endef test-sim-nondeterminism: - $(call run-sim-test,"non-determinism test",TestAppStateDeterminism,100,200,2h) + $(call run-sim-test,"non-determinism test",TestAppStateDeterminism,10,20,2h) test-sim-fullappsimulation: $(call run-sim-test,"TestFullAppSimulation",TestFullAppSimulation,100,200,2h) @@ -400,7 +400,13 @@ test-sim-multi-seed-short: runsim @echo "Running short multi-seed application simulation." @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation +test-sim-import: + $(call run-sim-test,"test-import",TestAppImportExport,10,20,2h) +test-sim-import-export: export GOFLAGS=-tags=objstore +test-sim-import-export: runsim + @echo "Running application import/export simulation. This may take several minutes..." + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppImportExport .PHONY: \ test-sim-nondeterminism \ diff --git a/app/app.go b/app/app.go index 1e64321f21..de42e6eee7 100644 --- a/app/app.go +++ b/app/app.go @@ -929,6 +929,10 @@ func (app *App) GetKey(storeKey string) *storetypes.KVStoreKey { return app.keys[storeKey] } +func (app *App) GetKeys() map[string]*storetypes.KVStoreKey { + return app.keys +} + // GetTKey returns the TransientStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. @@ -1060,6 +1064,10 @@ func (app *App) BasicManager() module.BasicManager { return app.mb } +func (app *App) ModuleManager() *module.Manager { + return app.mm +} + func (app *App) BlockedAddrs() map[string]bool { blockList := make(map[string]bool) diff --git a/tests/simulation/sim/sim_utils.go b/tests/simulation/sim/sim_utils.go index b310d7cae2..5530ea1f73 100644 --- a/tests/simulation/sim/sim_utils.go +++ b/tests/simulation/sim/sim_utils.go @@ -1,12 +1,16 @@ package sim import ( + "encoding/json" "fmt" + "os" dbm "github.com/cometbft/cometbft-db" "github.com/cometbft/cometbft/libs/log" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/runtime" servertypes "github.com/cosmos/cosmos-sdk/server/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/zeta-chain/ethermint/app" evmante "github.com/zeta-chain/ethermint/app/ante" @@ -66,3 +70,32 @@ func PrintStats(db dbm.DB) { fmt.Println(db.Stats()["leveldb.stats"]) fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) } + +// CheckExportSimulation exports the app state and simulation parameters to JSON +// if the export paths are defined. +func CheckExportSimulation(app runtime.AppI, config simtypes.Config, params simtypes.Params) error { + if config.ExportStatePath != "" { + fmt.Println("exporting app state...") + exported, err := app.ExportAppStateAndValidators(false, nil, nil) + if err != nil { + return err + } + + if err := os.WriteFile(config.ExportStatePath, []byte(exported.AppState), 0o600); err != nil { + return err + } + } + + if config.ExportParamsPath != "" { + fmt.Println("exporting simulation params...") + paramsBz, err := json.MarshalIndent(params, "", " ") + if err != nil { + return err + } + + if err := os.WriteFile(config.ExportParamsPath, paramsBz, 0o600); err != nil { + return err + } + } + return nil +} diff --git a/tests/simulation/sim/sim_utils_cosmos.go b/tests/simulation/sim/sim_utils_cosmos.go new file mode 100644 index 0000000000..3f2ac0ee22 --- /dev/null +++ b/tests/simulation/sim/sim_utils_cosmos.go @@ -0,0 +1,114 @@ +package sim + +import ( + "bytes" + "fmt" + "sync" + + dbm "github.com/cometbft/cometbft-db" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/types/kv" +) + +// DiffKVStores compares two KVstores and returns all the key/value pairs +// that differ from one another. It also skips value comparison for a set of provided prefixes. +func DiffKVStores(a, b storetypes.KVStore, prefixesToSkip [][]byte) (diffA, diffB []kv.Pair) { + iterA := a.Iterator(nil, nil) + defer iterA.Close() + + iterB := b.Iterator(nil, nil) + defer iterB.Close() + + var wg sync.WaitGroup + + wg.Add(1) + kvAs := make([]kv.Pair, 0) + go func() { + defer wg.Done() + kvAs = getKVPairs(iterA, prefixesToSkip) + }() + + wg.Add(1) + kvBs := make([]kv.Pair, 0) + go func() { + defer wg.Done() + kvBs = getKVPairs(iterB, prefixesToSkip) + }() + + wg.Wait() + + if len(kvAs) != len(kvBs) { + fmt.Printf("KV stores are different: %d key/value pairs in store A and %d key/value pairs in store B\n", len(kvAs), len(kvBs)) + } + + return getDiffFromKVPair(kvAs, kvBs) +} + +// getDiffFromKVPair compares two KVstores and returns all the key/value pairs +func getDiffFromKVPair(kvAs, kvBs []kv.Pair) (diffA, diffB []kv.Pair) { + // we assume that kvBs is equal or larger than kvAs + // if not, we swap the two + if len(kvAs) > len(kvBs) { + kvAs, kvBs = kvBs, kvAs + // we need to swap the diffA and diffB as well + defer func() { + diffA, diffB = diffB, diffA + }() + } + + // in case kvAs is empty we can return early + // since there is nothing to compare + // if kvAs == kvBs, then diffA and diffB will be empty + if len(kvAs) == 0 { + return []kv.Pair{}, kvBs + } + + index := make(map[string][]byte, len(kvBs)) + for _, kv := range kvBs { + index[string(kv.Key)] = kv.Value + } + + for _, kvA := range kvAs { + if kvBValue, ok := index[string(kvA.Key)]; !ok { + diffA = append(diffA, kvA) + diffB = append(diffB, kv.Pair{Key: kvA.Key}) // the key is missing from kvB so we append a pair with an empty value + } else if !bytes.Equal(kvA.Value, kvBValue) { + diffA = append(diffA, kvA) + diffB = append(diffB, kv.Pair{Key: kvA.Key, Value: kvBValue}) + } else { + // values are equal, so we remove the key from the index + delete(index, string(kvA.Key)) + } + } + + // add the remaining keys from kvBs + for key, value := range index { + diffA = append(diffA, kv.Pair{Key: []byte(key)}) // the key is missing from kvA so we append a pair with an empty value + diffB = append(diffB, kv.Pair{Key: []byte(key), Value: value}) + } + + return diffA, diffB +} + +func getKVPairs(iter dbm.Iterator, prefixesToSkip [][]byte) (kvs []kv.Pair) { + for iter.Valid() { + key, value := iter.Key(), iter.Value() + + // do not add the KV pair if the key is prefixed to be skipped. + skip := false + for _, prefix := range prefixesToSkip { + if bytes.HasPrefix(key, prefix) { + skip = true + break + } + } + + if !skip { + kvs = append(kvs, kv.Pair{Key: key, Value: value}) + } + + iter.Next() + } + + return kvs +} diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 957e92081a..5a619a1f48 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -2,11 +2,27 @@ package simulation_test import ( "encoding/json" + "fmt" "math/rand" "os" + "runtime/debug" + "strings" "testing" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + evmtypes "github.com/zeta-chain/ethermint/x/evm/types" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/app" simutils "github.com/zeta-chain/node/tests/simulation/sim" "github.com/cosmos/cosmos-sdk/store" @@ -26,6 +42,12 @@ func init() { simutils.GetSimulatorFlags() } +type StoreKeysPrefixes struct { + A storetypes.StoreKey + B storetypes.StoreKey + Prefixes [][]byte +} + const ( SimAppChainID = "simulation_777-1" SimBlockMaxGas = 815000000 @@ -79,7 +101,7 @@ func TestAppStateDeterminism(t *testing.T) { if config.Seed == cosmossimcli.DefaultSeedValue { config.Seed = rand.Int63() } - // For the same seed, the app hash produced at the end of each run should be the same + // For the same seed, the simApp hash produced at the end of each run should be the same for j := 0; j < numTimesToRunPerSeed; j++ { db, dir, logger, _, err := cosmossimutils.SetupSimulation( config, @@ -150,7 +172,7 @@ func TestAppStateDeterminism(t *testing.T) { } } -// TestFullAppSimulation runs a full app simulation with the provided configuration. +// TestFullAppSimulation runs a full simApp simulation with the provided configuration. // At the end of the run it tries to export the genesis state to make sure the export works. func TestFullAppSimulation(t *testing.T) { @@ -211,3 +233,142 @@ func TestFullAppSimulation(t *testing.T) { simutils.PrintStats(db) } + +func TestAppImportExport(t *testing.T) { + config := simutils.NewConfigFromFlags() + + config.ChainID = SimAppChainID + config.BlockMaxGas = SimBlockMaxGas + config.DBBackend = SimDBBackend + + db, dir, logger, skip, err := cosmossimutils.SetupSimulation( + config, + SimDBBackend, + SimDBName, + simutils.FlagVerboseValue, + simutils.FlagEnabledValue, + ) + if skip { + t.Skip("skipping application simulation") + } + require.NoError(t, err, "simulation setup failed") + + defer func() { + require.NoError(t, db.Close()) + require.NoError(t, os.RemoveAll(dir)) + }() + + appOptions := make(cosmossimutils.AppOptionsMap, 0) + appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue + appOptions[flags.FlagHome] = dir + simApp, err := simutils.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + require.NoError(t, err) + + // Run randomized simulation + blockedAddresses := simApp.ModuleAccountAddrs() + _, simparams, simerr := simulation.SimulateFromSeed( + t, + os.Stdout, + simApp.BaseApp, + simutils.AppStateFn( + simApp.AppCodec(), + simApp.SimulationManager(), + simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), + ), + cosmossim.RandomAccounts, + cosmossimutils.SimulationOperations(simApp, simApp.AppCodec(), config), + blockedAddresses, + config, + simApp.AppCodec(), + ) + require.NoError(t, simerr) + + // export state and simParams before the simulation error is checked + err = simutils.CheckExportSimulation(simApp, config, simparams) + require.NoError(t, err) + + simutils.PrintStats(db) + + t.Log("exporting genesis") + + exported, err := simApp.ExportAppStateAndValidators(false, []string{}, []string{}) + require.NoError(t, err) + + t.Log("importing genesis") + + newDB, newDir, _, _, err := cosmossimutils.SetupSimulation( + config, + SimDBBackend, + SimDBName, + simutils.FlagVerboseValue, + simutils.FlagEnabledValue, + ) + + require.NoError(t, err, "simulation setup failed") + + defer func() { + require.NoError(t, newDB.Close()) + require.NoError(t, os.RemoveAll(newDir)) + }() + + newSimApp, err := simutils.NewSimApp(logger, newDB, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + require.NoError(t, err) + + var genesisState app.GenesisState + err = json.Unmarshal(exported.AppState, &genesisState) + require.NoError(t, err) + + defer func() { + if r := recover(); r != nil { + err := fmt.Sprintf("%v", r) + if !strings.Contains(err, "validator set is empty after InitGenesis") { + panic(r) + } + logger.Info("Skipping simulation as all validators have been unbonded") + logger.Info("err", err, "stacktrace", string(debug.Stack())) + } + }() + + ctxA := simApp.NewContext(true, tmproto.Header{ + Height: simApp.LastBlockHeight(), + ChainID: SimAppChainID, + }).WithChainID(SimAppChainID) + ctxB := newSimApp.NewContext(true, tmproto.Header{ + Height: simApp.LastBlockHeight(), + ChainID: SimAppChainID, + }).WithChainID(SimAppChainID) + newSimApp.ModuleManager().InitGenesis(ctxB, newSimApp.AppCodec(), genesisState) + newSimApp.StoreConsensusParams(ctxB, exported.ConsensusParams) + + t.Log("comparing stores") + + storeKeysPrefixes := []StoreKeysPrefixes{ + + {simApp.GetKey(authtypes.StoreKey), newSimApp.GetKey(authtypes.StoreKey), [][]byte{}}, + { + simApp.GetKey(stakingtypes.StoreKey), newSimApp.GetKey(stakingtypes.StoreKey), + [][]byte{ + stakingtypes.UnbondingQueueKey, stakingtypes.RedelegationQueueKey, stakingtypes.ValidatorQueueKey, + stakingtypes.HistoricalInfoKey, stakingtypes.UnbondingIDKey, stakingtypes.UnbondingIndexKey, stakingtypes.UnbondingTypeKey, stakingtypes.ValidatorUpdatesKey, + }, + }, // ordering may change but it doesn't matter + {simApp.GetKey(slashingtypes.StoreKey), newSimApp.GetKey(slashingtypes.StoreKey), [][]byte{}}, + {simApp.GetKey(distrtypes.StoreKey), newSimApp.GetKey(distrtypes.StoreKey), [][]byte{}}, + {simApp.GetKey(banktypes.StoreKey), newSimApp.GetKey(banktypes.StoreKey), [][]byte{banktypes.BalancesPrefix}}, + {simApp.GetKey(paramtypes.StoreKey), newSimApp.GetKey(paramtypes.StoreKey), [][]byte{}}, + {simApp.GetKey(govtypes.StoreKey), newSimApp.GetKey(govtypes.StoreKey), [][]byte{}}, + {simApp.GetKey(evidencetypes.StoreKey), newSimApp.GetKey(evidencetypes.StoreKey), [][]byte{}}, + {simApp.GetKey(evmtypes.StoreKey), newSimApp.GetKey(evmtypes.StoreKey), [][]byte{}}, + } + + for _, skp := range storeKeysPrefixes { + storeA := ctxA.KVStore(skp.A) + storeB := ctxB.KVStore(skp.B) + + failedKVAs, failedKVBs := simutils.DiffKVStores(storeA, storeB, skp.Prefixes) + require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare") + + fmt.Printf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B) + require.Equal(t, 0, len(failedKVAs), cosmossimutils.GetSimulationLog(skp.A.Name(), simApp.SimulationManager().StoreDecoders, failedKVAs, failedKVBs)) + } +} From 651a61a0bff86d1c108a56fa754b4dab5e28cc46 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 22 Oct 2024 13:35:19 -0400 Subject: [PATCH 24/59] test sim after import --- Makefile | 8 ++- tests/simulation/sim_test.go | 115 ++++++++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 3ac53b338e..9d2f82db77 100644 --- a/Makefile +++ b/Makefile @@ -392,6 +392,12 @@ test-sim-nondeterminism: test-sim-fullappsimulation: $(call run-sim-test,"TestFullAppSimulation",TestFullAppSimulation,100,200,2h) +test-sim-import-export-local: + $(call run-sim-test,"test-import",TestAppImportExport,10,20,2h) + +test-sim-after-import-local: + $(call run-sim-test,"test-sim-after-import",TestAppSimulationAfterImport,10,20,2h) + test-sim-multi-seed-long: runsim @echo "Running long multi-seed application simulation." @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestFullAppSimulation @@ -400,8 +406,6 @@ test-sim-multi-seed-short: runsim @echo "Running short multi-seed application simulation." @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation -test-sim-import: - $(call run-sim-test,"test-import",TestAppImportExport,10,20,2h) test-sim-import-export: export GOFLAGS=-tags=objstore test-sim-import-export: runsim diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 5a619a1f48..9b121a1968 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -9,6 +9,7 @@ import ( "strings" "testing" + abci "github.com/cometbft/cometbft/abci/types" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" storetypes "github.com/cosmos/cosmos-sdk/store/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -298,8 +299,8 @@ func TestAppImportExport(t *testing.T) { newDB, newDir, _, _, err := cosmossimutils.SetupSimulation( config, - SimDBBackend, - SimDBName, + SimDBBackend+"_new", + SimDBName+"_new", simutils.FlagVerboseValue, simutils.FlagEnabledValue, ) @@ -368,7 +369,115 @@ func TestAppImportExport(t *testing.T) { failedKVAs, failedKVBs := simutils.DiffKVStores(storeA, storeB, skp.Prefixes) require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare") - fmt.Printf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B) + t.Logf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B) require.Equal(t, 0, len(failedKVAs), cosmossimutils.GetSimulationLog(skp.A.Name(), simApp.SimulationManager().StoreDecoders, failedKVAs, failedKVBs)) } } + +func TestAppSimulationAfterImport(t *testing.T) { + config := simutils.NewConfigFromFlags() + + config.ChainID = SimAppChainID + config.BlockMaxGas = SimBlockMaxGas + config.DBBackend = SimDBBackend + + db, dir, logger, skip, err := cosmossimutils.SetupSimulation( + config, + SimDBBackend, + SimDBName, + simutils.FlagVerboseValue, + simutils.FlagEnabledValue, + ) + if skip { + t.Skip("skipping application simulation") + } + require.NoError(t, err, "simulation setup failed") + + defer func() { + require.NoError(t, db.Close()) + require.NoError(t, os.RemoveAll(dir)) + }() + + appOptions := make(cosmossimutils.AppOptionsMap, 0) + appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue + appOptions[flags.FlagHome] = dir + simApp, err := simutils.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + require.NoError(t, err) + + // Run randomized simulation + blockedAddresses := simApp.ModuleAccountAddrs() + stopEarly, simParams, simerr := simulation.SimulateFromSeed( + t, + os.Stdout, + simApp.BaseApp, + simutils.AppStateFn( + simApp.AppCodec(), + simApp.SimulationManager(), + simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), + ), + cosmossim.RandomAccounts, + cosmossimutils.SimulationOperations(simApp, simApp.AppCodec(), config), + blockedAddresses, + config, + simApp.AppCodec(), + ) + require.NoError(t, simerr) + + // export state and simParams before the simulation error is checked + err = simutils.CheckExportSimulation(simApp, config, simParams) + require.NoError(t, err) + + simutils.PrintStats(db) + + if stopEarly { + t.Log("can't export or import a zero-validator genesis, exiting test") + return + } + + t.Log("exporting genesis") + + exported, err := simApp.ExportAppStateAndValidators(true, []string{}, []string{}) + require.NoError(t, err) + + t.Log("importing genesis") + + newDB, newDir, _, _, err := cosmossimutils.SetupSimulation( + config, + SimDBBackend+"_new", + SimDBName+"_new", + simutils.FlagVerboseValue, + simutils.FlagEnabledValue, + ) + + require.NoError(t, err, "simulation setup failed") + + defer func() { + require.NoError(t, newDB.Close()) + require.NoError(t, os.RemoveAll(newDir)) + }() + + newSimApp, err := simutils.NewSimApp(logger, newDB, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + require.NoError(t, err) + + newSimApp.InitChain(abci.RequestInitChain{ + ChainId: SimAppChainID, + AppStateBytes: exported.AppState, + }) + + stopEarly, simParams, simerr = simulation.SimulateFromSeed( + t, + os.Stdout, + newSimApp.BaseApp, + simutils.AppStateFn( + simApp.AppCodec(), + simApp.SimulationManager(), + simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), + ), + cosmossim.RandomAccounts, + cosmossimutils.SimulationOperations(newSimApp, newSimApp.AppCodec(), config), + blockedAddresses, + config, + simApp.AppCodec(), + ) + require.NoError(t, err) +} From 5e3bce774a46f6da0e4e1ecb05ec79c5ddb13db4 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 22 Oct 2024 18:39:36 -0400 Subject: [PATCH 25/59] add bench test --- Makefile | 13 +++-- app/export.go | 7 +-- tests/simulation/sim_bench_test.go | 78 ++++++++++++++++++++++++++++++ tests/simulation/sim_test.go | 18 +++---- 4 files changed, 98 insertions(+), 18 deletions(-) create mode 100644 tests/simulation/sim_bench_test.go diff --git a/Makefile b/Makefile index 9d2f82db77..a14c40a2ec 100644 --- a/Makefile +++ b/Makefile @@ -392,10 +392,10 @@ test-sim-nondeterminism: test-sim-fullappsimulation: $(call run-sim-test,"TestFullAppSimulation",TestFullAppSimulation,100,200,2h) -test-sim-import-export-local: +test-sim-import-export: $(call run-sim-test,"test-import",TestAppImportExport,10,20,2h) -test-sim-after-import-local: +test-sim-after-import: $(call run-sim-test,"test-sim-after-import",TestAppSimulationAfterImport,10,20,2h) test-sim-multi-seed-long: runsim @@ -407,11 +407,16 @@ test-sim-multi-seed-short: runsim @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation -test-sim-import-export: export GOFLAGS=-tags=objstore -test-sim-import-export: runsim +test-sim-import-export-long: export GOFLAGS=-tags=objstore +test-sim-import-export-long: runsim @echo "Running application import/export simulation. This may take several minutes..." @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppImportExport +test-sim-after-import-long: export GOFLAGS=-tags=objstore +test-sim-after-import-long: runsim + @echo "Running application simulation-after-import. This may take several minutes..." + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppSimulationAfterImport + .PHONY: \ test-sim-nondeterminism \ test-sim-fullappsimulation \ diff --git a/app/export.go b/app/export.go index 1f1ae26a96..037ad6f161 100644 --- a/app/export.go +++ b/app/export.go @@ -75,10 +75,7 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []str // withdraw all validator commission app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { - _, err := app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator()) - if err != nil { - panic(err) - } + _, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator()) return false }) @@ -162,7 +159,7 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []str counter := int16(0) for ; iter.Valid(); iter.Next() { - addr := sdk.ValAddress(iter.Key()[1:]) + addr := sdk.ValAddress(iter.Key()[2:]) validator, found := app.StakingKeeper.GetValidator(ctx, addr) if !found { panic("expected validator, not found") diff --git a/tests/simulation/sim_bench_test.go b/tests/simulation/sim_bench_test.go new file mode 100644 index 0000000000..466f2552bf --- /dev/null +++ b/tests/simulation/sim_bench_test.go @@ -0,0 +1,78 @@ +package simulation_test + +import ( + "os" + "testing" + + cosmossim "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/stretchr/testify/require" + simutils "github.com/zeta-chain/node/tests/simulation/sim" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/server" + cosmossimutils "github.com/cosmos/cosmos-sdk/testutil/sims" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +func BenchmarkFullAppSimulation(b *testing.B) { + b.ReportAllocs() + + config := simutils.NewConfigFromFlags() + + config.ChainID = SimAppChainID + config.BlockMaxGas = SimBlockMaxGas + config.DBBackend = SimDBBackend + + db, dir, logger, skip, err := cosmossimutils.SetupSimulation( + config, + SimDBBackend, + SimDBName, + simutils.FlagVerboseValue, + simutils.FlagEnabledValue, + ) + if skip { + b.Skip("skipping application simulation") + } + require.NoError(b, err, "simulation setup failed") + + defer func() { + require.NoError(b, db.Close()) + require.NoError(b, os.RemoveAll(dir)) + }() + + appOptions := make(cosmossimutils.AppOptionsMap, 0) + appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue + appOptions[flags.FlagHome] = dir + simApp, err := simutils.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + require.NoError(b, err) + + // Run randomized simulation: + blockedAddresses := simApp.ModuleAccountAddrs() + _, simParams, simErr := simulation.SimulateFromSeed( + b, + os.Stdout, + simApp.BaseApp, + simutils.AppStateFn( + simApp.AppCodec(), + simApp.SimulationManager(), + simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), + ), + cosmossim.RandomAccounts, + cosmossimutils.SimulationOperations(simApp, simApp.AppCodec(), config), + blockedAddresses, + config, + simApp.AppCodec(), + ) + require.NoError(b, simErr) + + // export state and simParams before the simulation error is checked + err = simutils.CheckExportSimulation(simApp, config, simParams) + require.NoError(b, err) + + if simErr != nil { + b.Fatal(simErr) + } + + simutils.PrintStats(db) +} diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 9b121a1968..64e280d687 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -207,7 +207,7 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, err) blockedAddresses := simApp.ModuleAccountAddrs() - _, _, simerr := simulation.SimulateFromSeed( + _, _, simErr := simulation.SimulateFromSeed( t, os.Stdout, simApp.BaseApp, @@ -222,7 +222,7 @@ func TestFullAppSimulation(t *testing.T) { config, simApp.AppCodec(), ) - require.NoError(t, simerr) + require.NoError(t, simErr) // check export works as expected exported, err := simApp.ExportAppStateAndValidators(false, nil, nil) @@ -267,7 +267,7 @@ func TestAppImportExport(t *testing.T) { // Run randomized simulation blockedAddresses := simApp.ModuleAccountAddrs() - _, simparams, simerr := simulation.SimulateFromSeed( + _, simParams, simErr := simulation.SimulateFromSeed( t, os.Stdout, simApp.BaseApp, @@ -282,10 +282,10 @@ func TestAppImportExport(t *testing.T) { config, simApp.AppCodec(), ) - require.NoError(t, simerr) + require.NoError(t, simErr) // export state and simParams before the simulation error is checked - err = simutils.CheckExportSimulation(simApp, config, simparams) + err = simutils.CheckExportSimulation(simApp, config, simParams) require.NoError(t, err) simutils.PrintStats(db) @@ -406,7 +406,7 @@ func TestAppSimulationAfterImport(t *testing.T) { // Run randomized simulation blockedAddresses := simApp.ModuleAccountAddrs() - stopEarly, simParams, simerr := simulation.SimulateFromSeed( + stopEarly, simParams, simErr := simulation.SimulateFromSeed( t, os.Stdout, simApp.BaseApp, @@ -421,7 +421,7 @@ func TestAppSimulationAfterImport(t *testing.T) { config, simApp.AppCodec(), ) - require.NoError(t, simerr) + require.NoError(t, simErr) // export state and simParams before the simulation error is checked err = simutils.CheckExportSimulation(simApp, config, simParams) @@ -430,7 +430,7 @@ func TestAppSimulationAfterImport(t *testing.T) { simutils.PrintStats(db) if stopEarly { - t.Log("can't export or import a zero-validator genesis, exiting test") + fmt.Println("can't export or import a zero-validator genesis, exiting test...") return } @@ -464,7 +464,7 @@ func TestAppSimulationAfterImport(t *testing.T) { AppStateBytes: exported.AppState, }) - stopEarly, simParams, simerr = simulation.SimulateFromSeed( + stopEarly, simParams, simErr = simulation.SimulateFromSeed( t, os.Stdout, newSimApp.BaseApp, From 3b44c10c7ca2e2c21208e1bf22e7a80afcc6ab02 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 22 Oct 2024 20:12:04 -0400 Subject: [PATCH 26/59] remove bench --- Makefile | 2 +- tests/simulation/sim_bench_test.go | 78 ------------------------------ 2 files changed, 1 insertion(+), 79 deletions(-) delete mode 100644 tests/simulation/sim_bench_test.go diff --git a/Makefile b/Makefile index a14c40a2ec..071950758a 100644 --- a/Makefile +++ b/Makefile @@ -381,7 +381,7 @@ $(BINDIR)/runsim: # Period: Invariant check period # Timeout: Timeout for the simulation test define run-sim-test - @echo "Running $(1)..." + @echo "Running $(1)" @go test -mod=readonly $(SIMAPP) -run $(2) -Enabled=true \ -NumBlocks=$(3) -BlockSize=$(4) -Commit=true -Period=0 -v -timeout $(5) endef diff --git a/tests/simulation/sim_bench_test.go b/tests/simulation/sim_bench_test.go deleted file mode 100644 index 466f2552bf..0000000000 --- a/tests/simulation/sim_bench_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package simulation_test - -import ( - "os" - "testing" - - cosmossim "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/stretchr/testify/require" - simutils "github.com/zeta-chain/node/tests/simulation/sim" - - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/server" - cosmossimutils "github.com/cosmos/cosmos-sdk/testutil/sims" - "github.com/cosmos/cosmos-sdk/x/simulation" -) - -func BenchmarkFullAppSimulation(b *testing.B) { - b.ReportAllocs() - - config := simutils.NewConfigFromFlags() - - config.ChainID = SimAppChainID - config.BlockMaxGas = SimBlockMaxGas - config.DBBackend = SimDBBackend - - db, dir, logger, skip, err := cosmossimutils.SetupSimulation( - config, - SimDBBackend, - SimDBName, - simutils.FlagVerboseValue, - simutils.FlagEnabledValue, - ) - if skip { - b.Skip("skipping application simulation") - } - require.NoError(b, err, "simulation setup failed") - - defer func() { - require.NoError(b, db.Close()) - require.NoError(b, os.RemoveAll(dir)) - }() - - appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue - appOptions[flags.FlagHome] = dir - simApp, err := simutils.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) - require.NoError(b, err) - - // Run randomized simulation: - blockedAddresses := simApp.ModuleAccountAddrs() - _, simParams, simErr := simulation.SimulateFromSeed( - b, - os.Stdout, - simApp.BaseApp, - simutils.AppStateFn( - simApp.AppCodec(), - simApp.SimulationManager(), - simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), - ), - cosmossim.RandomAccounts, - cosmossimutils.SimulationOperations(simApp, simApp.AppCodec(), config), - blockedAddresses, - config, - simApp.AppCodec(), - ) - require.NoError(b, simErr) - - // export state and simParams before the simulation error is checked - err = simutils.CheckExportSimulation(simApp, config, simParams) - require.NoError(b, err) - - if simErr != nil { - b.Fatal(simErr) - } - - simutils.PrintStats(db) -} From 6eea359468c49ec4c235e7291a28a4086c46b460 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 23 Oct 2024 08:46:37 -0400 Subject: [PATCH 27/59] add changelog --- Makefile | 13 ++++++------ changelog.md | 1 + docs/development/SIMULATION_TESTING.md | 29 +++++++++++++++++++++++--- tests/simulation/sim_test.go | 2 +- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 071950758a..d2e991a14a 100644 --- a/Makefile +++ b/Makefile @@ -406,22 +406,23 @@ test-sim-multi-seed-short: runsim @echo "Running short multi-seed application simulation." @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation - -test-sim-import-export-long: export GOFLAGS=-tags=objstore test-sim-import-export-long: runsim - @echo "Running application import/export simulation. This may take several minutes..." + @echo "Running application import/export simulation. This may take several minutes" @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppImportExport -test-sim-after-import-long: export GOFLAGS=-tags=objstore test-sim-after-import-long: runsim - @echo "Running application simulation-after-import. This may take several minutes..." + @echo "Running application simulation-after-import. This may take several minute" @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppSimulationAfterImport .PHONY: \ test-sim-nondeterminism \ test-sim-fullappsimulation \ test-sim-multi-seed-long \ -test-sim-multi-seed-short +test-sim-multi-seed-short \ +test-sim-import-export \ +test-sim-after-import \ +test-sim-import-export-long \ +test-sim-after-import-long ############################################################################### diff --git a/changelog.md b/changelog.md index b666c26f7d..836656e437 100644 --- a/changelog.md +++ b/changelog.md @@ -44,6 +44,7 @@ * [2894](https://github.com/zeta-chain/node/pull/2894) - increase gas limit for TSS vote tx * [2932](https://github.com/zeta-chain/node/pull/2932) - add gateway upgrade as part of the upgrade test * [2947](https://github.com/zeta-chain/node/pull/2947) - initialize simulation tests +* [3033](https://github.com/zeta-chain/node/pull/3033) - initialize simulation tests for import and export ### Fixes diff --git a/docs/development/SIMULATION_TESTING.md b/docs/development/SIMULATION_TESTING.md index 1f5232911a..29697378be 100644 --- a/docs/development/SIMULATION_TESTING.md +++ b/docs/development/SIMULATION_TESTING.md @@ -20,15 +20,38 @@ At the end of the run it tries to export the genesis state to make sure the expo ```bash make test-sim-full-app ``` - +### Import Export simulation test +The import export simulation test runs a full application simulation +and exports the application state at the end of the run. +This state is then then imported into a new simulation. +At the end of the run we compare the keys for the application state for both the simulations +to make sure they are the same. +```bash +make test-sim-import-export +``` +### Import and run simulation test +This simulation test exports the application state at the end of the run and imports it into a new simulation. +```bash +make test-sim-import-export +``` ### Multi seed long test Multi seed long test runs a full application simulation with multiple seeds and multiple blocks.This runs the test for a longer duration compared to the multi seed short test ```bash make test-sim-multi-seed-long ``` - ### Multi seed short test Multi seed short test runs a full application simulation with multiple seeds and multiple blocks. This runs the test for a longer duration compared to the multi seed long test ```bash make test-sim-multi-seed-short -``` \ No newline at end of file +``` +### Import Export long test +This test runs the import export simulation test for a longer duration.It uses the runsim tool to run the same test in parallel threads +```bash +make test-sim-import-export-long +``` +### Import and run simulation test +This test runs the import and run simulation test for a longer duration. It uses the runsim tool to run the same test in parallel threads +```bash +make test-sim-after-import-longg +``` + diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 64e280d687..7e0b6543ea 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -284,7 +284,7 @@ func TestAppImportExport(t *testing.T) { ) require.NoError(t, simErr) - // export state and simParams before the simulation error is checked + // export state and simParams err = simutils.CheckExportSimulation(simApp, config, simParams) require.NoError(t, err) From 9dfc005c3e654a0796fc04fc978273f3ba4e51b9 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 23 Oct 2024 11:10:06 -0400 Subject: [PATCH 28/59] remove cosmos utils --- Makefile | 2 +- tests/simulation/sim/sim_utils_cosmos.go | 114 ----------------------- tests/simulation/sim_test.go | 11 ++- 3 files changed, 7 insertions(+), 120 deletions(-) delete mode 100644 tests/simulation/sim/sim_utils_cosmos.go diff --git a/Makefile b/Makefile index d2e991a14a..e37fd14305 100644 --- a/Makefile +++ b/Makefile @@ -393,7 +393,7 @@ test-sim-fullappsimulation: $(call run-sim-test,"TestFullAppSimulation",TestFullAppSimulation,100,200,2h) test-sim-import-export: - $(call run-sim-test,"test-import",TestAppImportExport,10,20,2h) + $(call run-sim-test,"test-import-export",TestAppImportExport,10,20,2h) test-sim-after-import: $(call run-sim-test,"test-sim-after-import",TestAppSimulationAfterImport,10,20,2h) diff --git a/tests/simulation/sim/sim_utils_cosmos.go b/tests/simulation/sim/sim_utils_cosmos.go deleted file mode 100644 index 3f2ac0ee22..0000000000 --- a/tests/simulation/sim/sim_utils_cosmos.go +++ /dev/null @@ -1,114 +0,0 @@ -package sim - -import ( - "bytes" - "fmt" - "sync" - - dbm "github.com/cometbft/cometbft-db" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - "github.com/cosmos/cosmos-sdk/types/kv" -) - -// DiffKVStores compares two KVstores and returns all the key/value pairs -// that differ from one another. It also skips value comparison for a set of provided prefixes. -func DiffKVStores(a, b storetypes.KVStore, prefixesToSkip [][]byte) (diffA, diffB []kv.Pair) { - iterA := a.Iterator(nil, nil) - defer iterA.Close() - - iterB := b.Iterator(nil, nil) - defer iterB.Close() - - var wg sync.WaitGroup - - wg.Add(1) - kvAs := make([]kv.Pair, 0) - go func() { - defer wg.Done() - kvAs = getKVPairs(iterA, prefixesToSkip) - }() - - wg.Add(1) - kvBs := make([]kv.Pair, 0) - go func() { - defer wg.Done() - kvBs = getKVPairs(iterB, prefixesToSkip) - }() - - wg.Wait() - - if len(kvAs) != len(kvBs) { - fmt.Printf("KV stores are different: %d key/value pairs in store A and %d key/value pairs in store B\n", len(kvAs), len(kvBs)) - } - - return getDiffFromKVPair(kvAs, kvBs) -} - -// getDiffFromKVPair compares two KVstores and returns all the key/value pairs -func getDiffFromKVPair(kvAs, kvBs []kv.Pair) (diffA, diffB []kv.Pair) { - // we assume that kvBs is equal or larger than kvAs - // if not, we swap the two - if len(kvAs) > len(kvBs) { - kvAs, kvBs = kvBs, kvAs - // we need to swap the diffA and diffB as well - defer func() { - diffA, diffB = diffB, diffA - }() - } - - // in case kvAs is empty we can return early - // since there is nothing to compare - // if kvAs == kvBs, then diffA and diffB will be empty - if len(kvAs) == 0 { - return []kv.Pair{}, kvBs - } - - index := make(map[string][]byte, len(kvBs)) - for _, kv := range kvBs { - index[string(kv.Key)] = kv.Value - } - - for _, kvA := range kvAs { - if kvBValue, ok := index[string(kvA.Key)]; !ok { - diffA = append(diffA, kvA) - diffB = append(diffB, kv.Pair{Key: kvA.Key}) // the key is missing from kvB so we append a pair with an empty value - } else if !bytes.Equal(kvA.Value, kvBValue) { - diffA = append(diffA, kvA) - diffB = append(diffB, kv.Pair{Key: kvA.Key, Value: kvBValue}) - } else { - // values are equal, so we remove the key from the index - delete(index, string(kvA.Key)) - } - } - - // add the remaining keys from kvBs - for key, value := range index { - diffA = append(diffA, kv.Pair{Key: []byte(key)}) // the key is missing from kvA so we append a pair with an empty value - diffB = append(diffB, kv.Pair{Key: []byte(key), Value: value}) - } - - return diffA, diffB -} - -func getKVPairs(iter dbm.Iterator, prefixesToSkip [][]byte) (kvs []kv.Pair) { - for iter.Valid() { - key, value := iter.Key(), iter.Value() - - // do not add the KV pair if the key is prefixed to be skipped. - skip := false - for _, prefix := range prefixesToSkip { - if bytes.HasPrefix(key, prefix) { - skip = true - break - } - } - - if !skip { - kvs = append(kvs, kv.Pair{Key: key, Value: value}) - } - - iter.Next() - } - - return kvs -} diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 7e0b6543ea..c29172c20e 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -12,6 +12,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" @@ -296,7 +297,6 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, err) t.Log("importing genesis") - newDB, newDir, _, _, err := cosmossimutils.SetupSimulation( config, SimDBBackend+"_new", @@ -338,13 +338,14 @@ func TestAppImportExport(t *testing.T) { Height: simApp.LastBlockHeight(), ChainID: SimAppChainID, }).WithChainID(SimAppChainID) + + // Use genesis state from the first app to initialize the second app newSimApp.ModuleManager().InitGenesis(ctxB, newSimApp.AppCodec(), genesisState) newSimApp.StoreConsensusParams(ctxB, exported.ConsensusParams) t.Log("comparing stores") - + // The ordering of the keys is not important, we compare the same prefix for both simulations storeKeysPrefixes := []StoreKeysPrefixes{ - {simApp.GetKey(authtypes.StoreKey), newSimApp.GetKey(authtypes.StoreKey), [][]byte{}}, { simApp.GetKey(stakingtypes.StoreKey), newSimApp.GetKey(stakingtypes.StoreKey), @@ -352,7 +353,7 @@ func TestAppImportExport(t *testing.T) { stakingtypes.UnbondingQueueKey, stakingtypes.RedelegationQueueKey, stakingtypes.ValidatorQueueKey, stakingtypes.HistoricalInfoKey, stakingtypes.UnbondingIDKey, stakingtypes.UnbondingIndexKey, stakingtypes.UnbondingTypeKey, stakingtypes.ValidatorUpdatesKey, }, - }, // ordering may change but it doesn't matter + }, {simApp.GetKey(slashingtypes.StoreKey), newSimApp.GetKey(slashingtypes.StoreKey), [][]byte{}}, {simApp.GetKey(distrtypes.StoreKey), newSimApp.GetKey(distrtypes.StoreKey), [][]byte{}}, {simApp.GetKey(banktypes.StoreKey), newSimApp.GetKey(banktypes.StoreKey), [][]byte{banktypes.BalancesPrefix}}, @@ -366,7 +367,7 @@ func TestAppImportExport(t *testing.T) { storeA := ctxA.KVStore(skp.A) storeB := ctxB.KVStore(skp.B) - failedKVAs, failedKVBs := simutils.DiffKVStores(storeA, storeB, skp.Prefixes) + failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes) require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare") t.Logf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B) From a40f4d9a729441a5dca972a34b779e3b4127b1b0 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 23 Oct 2024 11:12:27 -0400 Subject: [PATCH 29/59] remove print lines --- tests/simulation/sim/sim_utils.go | 2 -- tests/simulation/sim_test.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/simulation/sim/sim_utils.go b/tests/simulation/sim/sim_utils.go index 5530ea1f73..a8d7ef7e61 100644 --- a/tests/simulation/sim/sim_utils.go +++ b/tests/simulation/sim/sim_utils.go @@ -75,7 +75,6 @@ func PrintStats(db dbm.DB) { // if the export paths are defined. func CheckExportSimulation(app runtime.AppI, config simtypes.Config, params simtypes.Params) error { if config.ExportStatePath != "" { - fmt.Println("exporting app state...") exported, err := app.ExportAppStateAndValidators(false, nil, nil) if err != nil { return err @@ -87,7 +86,6 @@ func CheckExportSimulation(app runtime.AppI, config simtypes.Config, params simt } if config.ExportParamsPath != "" { - fmt.Println("exporting simulation params...") paramsBz, err := json.MarshalIndent(params, "", " ") if err != nil { return err diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index c29172c20e..ea44278d6e 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -431,7 +431,7 @@ func TestAppSimulationAfterImport(t *testing.T) { simutils.PrintStats(db) if stopEarly { - fmt.Println("can't export or import a zero-validator genesis, exiting test...") + t.Log("can't export or import a zero-validator genesis, exiting test") return } From fdbacce9c7f8b4f6c5718662c5a5f60bff08e78c Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 23 Oct 2024 11:24:03 -0400 Subject: [PATCH 30/59] add comments --- tests/simulation/sim_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index ea44278d6e..d5893a9214 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -285,14 +285,13 @@ func TestAppImportExport(t *testing.T) { ) require.NoError(t, simErr) - // export state and simParams err = simutils.CheckExportSimulation(simApp, config, simParams) require.NoError(t, err) simutils.PrintStats(db) t.Log("exporting genesis") - + // export state and simParams exported, err := simApp.ExportAppStateAndValidators(false, []string{}, []string{}) require.NoError(t, err) @@ -424,7 +423,6 @@ func TestAppSimulationAfterImport(t *testing.T) { ) require.NoError(t, simErr) - // export state and simParams before the simulation error is checked err = simutils.CheckExportSimulation(simApp, config, simParams) require.NoError(t, err) @@ -437,6 +435,7 @@ func TestAppSimulationAfterImport(t *testing.T) { t.Log("exporting genesis") + // export state and simParams exported, err := simApp.ExportAppStateAndValidators(true, []string{}, []string{}) require.NoError(t, err) From a8684501f265fe8eab67ca13ed99dd6145782fab Mon Sep 17 00:00:00 2001 From: Julian Rubino Date: Wed, 23 Oct 2024 13:09:17 -0300 Subject: [PATCH 31/59] ci: Add simulation tests workflow --- .github/workflows/simulation-test.yaml | 75 ++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 .github/workflows/simulation-test.yaml diff --git a/.github/workflows/simulation-test.yaml b/.github/workflows/simulation-test.yaml new file mode 100644 index 0000000000..df700867be --- /dev/null +++ b/.github/workflows/simulation-test.yaml @@ -0,0 +1,75 @@ +name: Simulation Tests Workflow + +on: + # The workflow runs when code is pushed to either the main or develop branches + push: + branches: + - main + - develop + # The workflow runs when a pull request is opened or updated + pull_request: + # Run daily at 6AM UTC Daily + schedule: + - cron: "0 6 * * *" + # It can be run manually targetting a specific test + workflow_dispatch: + inputs: + test-target: + description: 'Makefile test target to run (e.g., test-sim-nondeterminism)' + required: true + default: 'test-sim-fullappsimulation' + +concurrency: + # Ensures that only one run of this workflow is active per branch or commit + group: runsim-${{ github.head_ref || github.sha }} + # If a new run is triggered for the same branch/commit while an old one is still in progress, the previous run will be canceled + cancel-in-progress: true + +jobs: + # This job is responsible for setting up the environment and installing the necessary dependencies, including runsim + install-dependencies: + runs-on: ubuntu-22.04 + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.20' + + - name: Install runsim and dependencies + run: | + make runsim + + run-simulation-tests: + needs: install-dependencies + runs-on: ubuntu-22.04 + strategy: + matrix: + # The matrix strategy allows running multiple simulation tests in parallel. In this case, it runs the following targets from the Makefile + test-target: [ + "test-sim-nondeterminism", + "test-sim-fullappsimulation", + "test-sim-import-export", + "test-sim-after-import" + ] + steps: + - name: Checkout code + uses: actions/checkout@v3 + + # It runs the specified test from the Makefile by calling make ${{ matrix.test-target }}, where test-target is one of the matrix values + - name: Run Simulation Test - ${{ matrix.test-target }} + run: | + make ${{ matrix.test-target }} + + manual-run: + runs-on: ubuntu-22.04 + if: github.event_name == 'workflow_dispatch' + steps: + - name: Checkout code + uses: actions/checkout@v3 + # This job only runs if the workflow was triggered by a manual dispatch (workflow_dispatch) + - name: Run Simulation Test - ${{ github.event.inputs.test-target }} + run: | + make ${{ github.event.inputs.test-target }} From bea00abbff7da3ae9124c4f22ab18ab9bb4c080d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 23 Oct 2024 12:50:29 -0400 Subject: [PATCH 32/59] merge ci workflow --- .github/workflows/simulation-test.yaml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/simulation-test.yaml b/.github/workflows/simulation-test.yaml index df700867be..a9c9717da9 100644 --- a/.github/workflows/simulation-test.yaml +++ b/.github/workflows/simulation-test.yaml @@ -1,17 +1,17 @@ name: Simulation Tests Workflow on: - # The workflow runs when code is pushed to either the main or develop branches - push: - branches: - - main - - develop - # The workflow runs when a pull request is opened or updated - pull_request: - # Run daily at 6AM UTC Daily - schedule: - - cron: "0 6 * * *" - # It can be run manually targetting a specific test +# # The workflow runs when code is pushed to either the main or develop branches +# push: +# branches: +# - main +# - develop +# # The workflow runs when a pull request is opened or updated +# pull_request: +# # Run daily at 6AM UTC Daily +# schedule: +# - cron: "0 6 * * *" +# # It can be run manually targetting a specific test workflow_dispatch: inputs: test-target: From 21b91d4a6852f6618a4f06e88141f3fdb5cdd3fd Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 23 Oct 2024 12:56:12 -0400 Subject: [PATCH 33/59] Update .github/workflows/simulation-test.yaml Co-authored-by: semgrep-code-zeta-chain[bot] <181804379+semgrep-code-zeta-chain[bot]@users.noreply.github.com> --- .github/workflows/simulation-test.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/simulation-test.yaml b/.github/workflows/simulation-test.yaml index a9c9717da9..eb5146218a 100644 --- a/.github/workflows/simulation-test.yaml +++ b/.github/workflows/simulation-test.yaml @@ -71,5 +71,8 @@ jobs: uses: actions/checkout@v3 # This job only runs if the workflow was triggered by a manual dispatch (workflow_dispatch) - name: Run Simulation Test - ${{ github.event.inputs.test-target }} - run: | - make ${{ github.event.inputs.test-target }} + - name: Run Simulation Test - ${{ github.event.inputs.test-target }} + env: + TEST_TARGET: ${{ github.event.inputs.test-target }} + run: | + make "$TEST_TARGET" From 59bc8863114552ad7277866270f52c43ecb20ba5 Mon Sep 17 00:00:00 2001 From: Julian Rubino Date: Thu, 24 Oct 2024 02:06:53 +0900 Subject: [PATCH 34/59] Update simulation-test.yaml Update simulation-test workflow --- .github/workflows/simulation-test.yaml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/simulation-test.yaml b/.github/workflows/simulation-test.yaml index eb5146218a..a8e755996e 100644 --- a/.github/workflows/simulation-test.yaml +++ b/.github/workflows/simulation-test.yaml @@ -48,12 +48,11 @@ jobs: strategy: matrix: # The matrix strategy allows running multiple simulation tests in parallel. In this case, it runs the following targets from the Makefile - test-target: [ - "test-sim-nondeterminism", - "test-sim-fullappsimulation", - "test-sim-import-export", - "test-sim-after-import" - ] + test-target: + - "test-sim-nondeterminism" + - "test-sim-fullappsimulation" + - "test-sim-import-export" + - "test-sim-after-import" steps: - name: Checkout code uses: actions/checkout@v3 @@ -71,8 +70,7 @@ jobs: uses: actions/checkout@v3 # This job only runs if the workflow was triggered by a manual dispatch (workflow_dispatch) - name: Run Simulation Test - ${{ github.event.inputs.test-target }} - - name: Run Simulation Test - ${{ github.event.inputs.test-target }} - env: - TEST_TARGET: ${{ github.event.inputs.test-target }} - run: | - make "$TEST_TARGET" + env: + TEST_TARGET: ${{ github.event.inputs.test-target }} + run: | + make "$TEST_TARGET" From 33bb1b988f1e8f2894500ce50048d70f628eccc6 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 23 Oct 2024 13:14:08 -0400 Subject: [PATCH 35/59] add branch sim-import-export to trigger ci run --- .github/workflows/simulation-test.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/simulation-test.yaml b/.github/workflows/simulation-test.yaml index a8e755996e..4cbef0a10b 100644 --- a/.github/workflows/simulation-test.yaml +++ b/.github/workflows/simulation-test.yaml @@ -1,9 +1,10 @@ name: Simulation Tests Workflow on: -# # The workflow runs when code is pushed to either the main or develop branches -# push: -# branches: + # The workflow runs when code is pushed to either the main or develop branches + push: + branches: + - sim-import-export # - main # - develop # # The workflow runs when a pull request is opened or updated From 9791e997846d63ebb5cf58e124ffecfab9879d52 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 23 Oct 2024 13:39:33 -0400 Subject: [PATCH 36/59] format files --- tests/simulation/sim_test.go | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index d5893a9214..0a7d44aac6 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -311,7 +311,13 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() - newSimApp, err := simutils.NewSimApp(logger, newDB, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + newSimApp, err := simutils.NewSimApp( + logger, + newDB, + appOptions, + interBlockCacheOpt(), + baseapp.SetChainID(SimAppChainID), + ) require.NoError(t, err) var genesisState app.GenesisState @@ -370,7 +376,17 @@ func TestAppImportExport(t *testing.T) { require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare") t.Logf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B) - require.Equal(t, 0, len(failedKVAs), cosmossimutils.GetSimulationLog(skp.A.Name(), simApp.SimulationManager().StoreDecoders, failedKVAs, failedKVBs)) + require.Equal( + t, + 0, + len(failedKVAs), + cosmossimutils.GetSimulationLog( + skp.A.Name(), + simApp.SimulationManager().StoreDecoders, + failedKVAs, + failedKVBs, + ), + ) } } @@ -456,7 +472,13 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() - newSimApp, err := simutils.NewSimApp(logger, newDB, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + newSimApp, err := simutils.NewSimApp( + logger, + newDB, + appOptions, + interBlockCacheOpt(), + baseapp.SetChainID(SimAppChainID), + ) require.NoError(t, err) newSimApp.InitChain(abci.RequestInitChain{ From 643490d6af604aeb9af9af6845ce155a87bf41f9 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 23 Oct 2024 18:26:07 -0400 Subject: [PATCH 37/59] uncomment simulation tests from CI --- .github/workflows/simulation-test.yaml | 17 ++++++++--------- Makefile | 8 ++++---- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/simulation-test.yaml b/.github/workflows/simulation-test.yaml index 4cbef0a10b..901a63039e 100644 --- a/.github/workflows/simulation-test.yaml +++ b/.github/workflows/simulation-test.yaml @@ -4,15 +4,14 @@ on: # The workflow runs when code is pushed to either the main or develop branches push: branches: - - sim-import-export -# - main -# - develop -# # The workflow runs when a pull request is opened or updated -# pull_request: -# # Run daily at 6AM UTC Daily -# schedule: -# - cron: "0 6 * * *" -# # It can be run manually targetting a specific test + - main + - develop + # The workflow runs when a pull request is opened or updated + pull_request: + # Run daily at 6AM UTC Daily + schedule: + - cron: "0 6 * * *" + # It can be run manually targetting a specific test workflow_dispatch: inputs: test-target: diff --git a/Makefile b/Makefile index e37fd14305..d052005c4c 100644 --- a/Makefile +++ b/Makefile @@ -387,16 +387,16 @@ define run-sim-test endef test-sim-nondeterminism: - $(call run-sim-test,"non-determinism test",TestAppStateDeterminism,10,20,2h) + $(call run-sim-test,"non-determinism test",TestAppStateDeterminism,100,200,30m) test-sim-fullappsimulation: - $(call run-sim-test,"TestFullAppSimulation",TestFullAppSimulation,100,200,2h) + $(call run-sim-test,"TestFullAppSimulation",TestFullAppSimulation,100,200,30m) test-sim-import-export: - $(call run-sim-test,"test-import-export",TestAppImportExport,10,20,2h) + $(call run-sim-test,"test-import-export",TestAppImportExport,100,200,30m) test-sim-after-import: - $(call run-sim-test,"test-sim-after-import",TestAppSimulationAfterImport,10,20,2h) + $(call run-sim-test,"test-sim-after-import",TestAppSimulationAfterImport,100,200,30m) test-sim-multi-seed-long: runsim @echo "Running long multi-seed application simulation." From 064e05ed3dd29a1f23e5730f622e874bed9ed9ef Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 23 Oct 2024 19:57:17 -0400 Subject: [PATCH 38/59] fix defer functions --- app/export.go | 7 ++++- docs/development/SIMULATION_TESTING.md | 10 +++---- tests/simulation/sim/sim_utils.go | 6 ++-- tests/simulation/sim_test.go | 40 +++++++++++++++++++------- 4 files changed, 44 insertions(+), 19 deletions(-) diff --git a/app/export.go b/app/export.go index 037ad6f161..50287e204d 100644 --- a/app/export.go +++ b/app/export.go @@ -159,7 +159,12 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []str counter := int16(0) for ; iter.Valid(); iter.Next() { - addr := sdk.ValAddress(iter.Key()[2:]) + key := iter.Key() + if len(key) <= 2 { + app.Logger().Error("unexpected key in staking store", "key", key) + continue + } + addr := sdk.ValAddress(key[2:]) validator, found := app.StakingKeeper.GetValidator(ctx, addr) if !found { panic("expected validator, not found") diff --git a/docs/development/SIMULATION_TESTING.md b/docs/development/SIMULATION_TESTING.md index 29697378be..1ff0ebd0af 100644 --- a/docs/development/SIMULATION_TESTING.md +++ b/docs/development/SIMULATION_TESTING.md @@ -23,7 +23,7 @@ make test-sim-full-app ### Import Export simulation test The import export simulation test runs a full application simulation and exports the application state at the end of the run. -This state is then then imported into a new simulation. +This state is then imported into a new simulation. At the end of the run we compare the keys for the application state for both the simulations to make sure they are the same. ```bash @@ -32,7 +32,7 @@ make test-sim-import-export ### Import and run simulation test This simulation test exports the application state at the end of the run and imports it into a new simulation. ```bash -make test-sim-import-export +make test-sim-after-import ``` ### Multi seed long test Multi seed long test runs a full application simulation with multiple seeds and multiple blocks.This runs the test for a longer duration compared to the multi seed short test @@ -40,7 +40,7 @@ Multi seed long test runs a full application simulation with multiple seeds and make test-sim-multi-seed-long ``` ### Multi seed short test -Multi seed short test runs a full application simulation with multiple seeds and multiple blocks. This runs the test for a longer duration compared to the multi seed long test +Multi seed short test runs a full application simulation with multiple seeds and multiple blocks. This runs the test for a shorter duration compared to the multi seed long test ```bash make test-sim-multi-seed-short ``` @@ -49,9 +49,9 @@ This test runs the import export simulation test for a longer duration.It uses t ```bash make test-sim-import-export-long ``` -### Import and run simulation test +### Import and run simulation test long This test runs the import and run simulation test for a longer duration. It uses the runsim tool to run the same test in parallel threads ```bash -make test-sim-after-import-longg +make test-sim-after-import-long ``` diff --git a/tests/simulation/sim/sim_utils.go b/tests/simulation/sim/sim_utils.go index a8d7ef7e61..e1ee19f307 100644 --- a/tests/simulation/sim/sim_utils.go +++ b/tests/simulation/sim/sim_utils.go @@ -77,10 +77,10 @@ func CheckExportSimulation(app runtime.AppI, config simtypes.Config, params simt if config.ExportStatePath != "" { exported, err := app.ExportAppStateAndValidators(false, nil, nil) if err != nil { - return err + return fmt.Errorf("failed to export app state: %w", err) } - if err := os.WriteFile(config.ExportStatePath, []byte(exported.AppState), 0o600); err != nil { + if err := os.WriteFile(config.ExportStatePath, exported.AppState, 0o600); err != nil { return err } } @@ -88,7 +88,7 @@ func CheckExportSimulation(app runtime.AppI, config simtypes.Config, params simt if config.ExportParamsPath != "" { paramsBz, err := json.MarshalIndent(params, "", " ") if err != nil { - return err + return fmt.Errorf("failed to write app state to %s: %w", config.ExportStatePath, err) } if err := os.WriteFile(config.ExportParamsPath, paramsBz, 0o600); err != nil { diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 0a7d44aac6..0bf39938c4 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -197,8 +197,12 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, err, "simulation setup failed") defer func() { - require.NoError(t, db.Close()) - require.NoError(t, os.RemoveAll(dir)) + if err := db.Close(); err != nil { + t.Errorf("Error closing new database: %v", err) + } + if err := os.RemoveAll(dir); err != nil { + t.Errorf("Error removing directory %s: %v", dir, err) + } }() appOptions := make(cosmossimutils.AppOptionsMap, 0) appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue @@ -256,8 +260,12 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, err, "simulation setup failed") defer func() { - require.NoError(t, db.Close()) - require.NoError(t, os.RemoveAll(dir)) + if err := db.Close(); err != nil { + t.Errorf("Error closing new database: %v", err) + } + if err := os.RemoveAll(dir); err != nil { + t.Errorf("Error removing directory %s: %v", dir, err) + } }() appOptions := make(cosmossimutils.AppOptionsMap, 0) @@ -307,8 +315,12 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, err, "simulation setup failed") defer func() { - require.NoError(t, newDB.Close()) - require.NoError(t, os.RemoveAll(newDir)) + if err := newDB.Close(); err != nil { + t.Errorf("Error closing new database: %v", err) + } + if err := os.RemoveAll(newDir); err != nil { + t.Errorf("Error removing directory %s: %v", newDir, err) + } }() newSimApp, err := simutils.NewSimApp( @@ -410,8 +422,12 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, err, "simulation setup failed") defer func() { - require.NoError(t, db.Close()) - require.NoError(t, os.RemoveAll(dir)) + if err := db.Close(); err != nil { + t.Errorf("Error closing new database: %v", err) + } + if err := os.RemoveAll(dir); err != nil { + t.Errorf("Error removing directory %s: %v", dir, err) + } }() appOptions := make(cosmossimutils.AppOptionsMap, 0) @@ -468,8 +484,12 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, err, "simulation setup failed") defer func() { - require.NoError(t, newDB.Close()) - require.NoError(t, os.RemoveAll(newDir)) + if err := newDB.Close(); err != nil { + t.Errorf("Error closing new database: %v", err) + } + if err := os.RemoveAll(newDir); err != nil { + t.Errorf("Error removing directory %s: %v", newDir, err) + } }() newSimApp, err := simutils.NewSimApp( From 57b5d4e07811dbf44b8cb66607673097fe64b25f Mon Sep 17 00:00:00 2001 From: Julian Rubino Date: Thu, 24 Oct 2024 12:25:26 -0300 Subject: [PATCH 39/59] Rename sim tests file, add result aggregation and merge jobs --- .github/workflows/sim.yaml | 90 ++++++++++++++++++++++++++ .github/workflows/simulation-test.yaml | 76 ---------------------- 2 files changed, 90 insertions(+), 76 deletions(-) create mode 100644 .github/workflows/sim.yaml delete mode 100644 .github/workflows/simulation-test.yaml diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml new file mode 100644 index 0000000000..c9b88fdeec --- /dev/null +++ b/.github/workflows/sim.yaml @@ -0,0 +1,90 @@ +name: Simulation Tests Workflow + +on: + push: + branches: + - main + - develop + pull_request: + schedule: + - cron: "0 6 * * *" + workflow_dispatch: + inputs: + make-targets: + description: 'Comma separated list of make targets to run (e.g., test-sim-nondeterminism, test-sim-fullappsimulation)' + required: true + default: '' + +concurrency: + group: simulation-${{ github.head_ref || github.sha }} + cancel-in-progress: true + +jobs: + matrix-conditionals: + runs-on: ubuntu-22.04 + outputs: + SIM_TEST_NOND: ${{ steps.matrix-conditionals.outputs.SIM_TEST_NOND }} + SIM_TEST_FULL: ${{ steps.matrix-conditionals.outputs.SIM_TEST_FULL }} + SIM_TEST_IMPORT_EXPORT: ${{ steps.matrix-conditionals.outputs.SIM_TEST_IMPORT_EXPORT }} + SIM_TEST_AFTER_IMPORT: ${{ steps.matrix-conditionals.outputs.SIM_TEST_AFTER_IMPORT }} + steps: + - id: matrix-conditionals + uses: actions/github-script@v7 + with: + script: | + const makeTargets = context.payload.inputs['make-targets'].split(','); + core.setOutput('SIM_TEST_NOND', makeTargets.includes('test-sim-nondeterminism')); + core.setOutput('SIM_TEST_FULL', makeTargets.includes('test-sim-fullappsimulation')); + core.setOutput('SIM_TEST_IMPORT_EXPORT', makeTargets.includes('test-sim-import-export')); + core.setOutput('SIM_TEST_AFTER_IMPORT', makeTargets.includes('test-sim-after-import')); + + simulation-tests: + needs: matrix-conditionals + strategy: + fail-fast: false + matrix: + include: + - make-target: "test-sim-nondeterminism" + runs-on: ubuntu-22.04 + run: ${{ needs.matrix-conditionals.outputs.SIM_TEST_NOND == 'true' }} + - make-target: "test-sim-fullappsimulation" + runs-on: ubuntu-22.04 + run: ${{ needs.matrix-conditionals.outputs.SIM_TEST_FULL == 'true' }} + - make-target: "test-sim-import-export" + runs-on: ubuntu-22.04 + run: ${{ needs.matrix-conditionals.outputs.SIM_TEST_IMPORT_EXPORT == 'true' }} + - make-target: "test-sim-after-import" + runs-on: ubuntu-22.04 + run: ${{ needs.matrix-conditionals.outputs.SIM_TEST_AFTER_IMPORT == 'true' }} + name: ${{ matrix.make-target }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.20' + + - name: Install dependencies + run: make runsim + + - name: Run ${{ matrix.make-target }} + run: | + make ${{ matrix.make-target }} + + sim-ok: + runs-on: ubuntu-22.04 + needs: + - matrix-conditionals + - simulation-tests + if: always() + steps: + - name: Aggregate Results + run: | + result="${{ needs.simulation-tests.result }}" + if [[ $result == "success" || $result == "skipped" ]]; then + exit 0 + else + exit 1 + fi diff --git a/.github/workflows/simulation-test.yaml b/.github/workflows/simulation-test.yaml deleted file mode 100644 index 901a63039e..0000000000 --- a/.github/workflows/simulation-test.yaml +++ /dev/null @@ -1,76 +0,0 @@ -name: Simulation Tests Workflow - -on: - # The workflow runs when code is pushed to either the main or develop branches - push: - branches: - - main - - develop - # The workflow runs when a pull request is opened or updated - pull_request: - # Run daily at 6AM UTC Daily - schedule: - - cron: "0 6 * * *" - # It can be run manually targetting a specific test - workflow_dispatch: - inputs: - test-target: - description: 'Makefile test target to run (e.g., test-sim-nondeterminism)' - required: true - default: 'test-sim-fullappsimulation' - -concurrency: - # Ensures that only one run of this workflow is active per branch or commit - group: runsim-${{ github.head_ref || github.sha }} - # If a new run is triggered for the same branch/commit while an old one is still in progress, the previous run will be canceled - cancel-in-progress: true - -jobs: - # This job is responsible for setting up the environment and installing the necessary dependencies, including runsim - install-dependencies: - runs-on: ubuntu-22.04 - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: '1.20' - - - name: Install runsim and dependencies - run: | - make runsim - - run-simulation-tests: - needs: install-dependencies - runs-on: ubuntu-22.04 - strategy: - matrix: - # The matrix strategy allows running multiple simulation tests in parallel. In this case, it runs the following targets from the Makefile - test-target: - - "test-sim-nondeterminism" - - "test-sim-fullappsimulation" - - "test-sim-import-export" - - "test-sim-after-import" - steps: - - name: Checkout code - uses: actions/checkout@v3 - - # It runs the specified test from the Makefile by calling make ${{ matrix.test-target }}, where test-target is one of the matrix values - - name: Run Simulation Test - ${{ matrix.test-target }} - run: | - make ${{ matrix.test-target }} - - manual-run: - runs-on: ubuntu-22.04 - if: github.event_name == 'workflow_dispatch' - steps: - - name: Checkout code - uses: actions/checkout@v3 - # This job only runs if the workflow was triggered by a manual dispatch (workflow_dispatch) - - name: Run Simulation Test - ${{ github.event.inputs.test-target }} - env: - TEST_TARGET: ${{ github.event.inputs.test-target }} - run: | - make "$TEST_TARGET" From 4b0dda4d553e24a0722e670d57ac8bbc8450974d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 24 Oct 2024 13:51:59 -0400 Subject: [PATCH 40/59] ignore simulation tests from codecov --- codecov.yml | 1 + docs/development/SIMULATION_TESTING.md | 28 +++++++++++++------ tests/simulation/sim_test.go | 37 +++++++++++++------------- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/codecov.yml b/codecov.yml index fee85c9c04..49cd96e8a0 100644 --- a/codecov.yml +++ b/codecov.yml @@ -81,3 +81,4 @@ ignore: - "precompiles/**/*.json" - "precompiles/**/*.sol" - "precompiles/**/*.gen.go" + - "tests/simulation/**/*" diff --git a/docs/development/SIMULATION_TESTING.md b/docs/development/SIMULATION_TESTING.md index 1ff0ebd0af..05eb0d4b98 100644 --- a/docs/development/SIMULATION_TESTING.md +++ b/docs/development/SIMULATION_TESTING.md @@ -1,25 +1,28 @@ # Zetachain simulation testing ## Overview The blockchain simulation tests how the blockchain application would behave under real life circumstances by generating -and sending randomized messages.The goal of this is to detect and debug failures that could halt a live chain,by providing -logs and statistics about the operations run by the simulator as well as exporting the latest application state. - +and sending randomized messages.The goal of this is to detect and debug failures that could halt a live chain,by +providing logs and statistics about the operations run by the simulator as well as exporting the latest application +state. ## Simulation tests ### Nondeterminism test Nondeterminism test runs a full application simulation , and produces multiple blocks as per the config It checks the determinism of the application by comparing the apphash at the end of each run to other runs -The test certifies that , for the same set of operations ( irrespective of what the operations are ), we would reach the same final state if the initial state is the same +The test certifies that , for the same set of operations ( irrespective of what the operations are ), we +would reach the same final state if the initial state is the same ```bash make test-sim-nondeterminism ``` + ### Full application simulation test Full application runs a full app simulation test with the provided configuration. At the end of the run it tries to export the genesis state to make sure the export works. ```bash make test-sim-full-app ``` + ### Import Export simulation test The import export simulation test runs a full application simulation and exports the application state at the end of the run. @@ -29,28 +32,37 @@ to make sure they are the same. ```bash make test-sim-import-export ``` + ### Import and run simulation test This simulation test exports the application state at the end of the run and imports it into a new simulation. ```bash make test-sim-after-import ``` + ### Multi seed long test -Multi seed long test runs a full application simulation with multiple seeds and multiple blocks.This runs the test for a longer duration compared to the multi seed short test +Multi seed long test runs a full application simulation with multiple seeds and multiple blocks. +This runs the test for a longer duration compared to the multi seed short test ```bash make test-sim-multi-seed-long ``` + ### Multi seed short test -Multi seed short test runs a full application simulation with multiple seeds and multiple blocks. This runs the test for a shorter duration compared to the multi seed long test +Multi seed short test runs a full application simulation with multiple seeds and multiple blocks. +This runs the test for a shorter duration compared to the multi seed long test ```bash make test-sim-multi-seed-short ``` + ### Import Export long test -This test runs the import export simulation test for a longer duration.It uses the runsim tool to run the same test in parallel threads +This test runs the import export simulation test for a longer duration. +It uses the runsim tool to run the same test in parallel threads ```bash make test-sim-import-export-long ``` + ### Import and run simulation test long -This test runs the import and run simulation test for a longer duration. It uses the runsim tool to run the same test in parallel threads +This test runs the import and run simulation test for a longer duration. +It uses the runsim tool to run the same test in parallel threads ```bash make test-sim-after-import-long ``` diff --git a/tests/simulation/sim_test.go b/tests/simulation/sim_test.go index 0bf39938c4..d8335fb8a9 100644 --- a/tests/simulation/sim_test.go +++ b/tests/simulation/sim_test.go @@ -198,10 +198,10 @@ func TestFullAppSimulation(t *testing.T) { defer func() { if err := db.Close(); err != nil { - t.Errorf("Error closing new database: %v", err) + require.NoError(t, err, "Error closing new database") } if err := os.RemoveAll(dir); err != nil { - t.Errorf("Error removing directory %s: %v", dir, err) + require.NoError(t, err, "Error removing directory") } }() appOptions := make(cosmossimutils.AppOptionsMap, 0) @@ -261,10 +261,10 @@ func TestAppImportExport(t *testing.T) { defer func() { if err := db.Close(); err != nil { - t.Errorf("Error closing new database: %v", err) + require.NoError(t, err, "Error closing new database") } if err := os.RemoveAll(dir); err != nil { - t.Errorf("Error removing directory %s: %v", dir, err) + require.NoError(t, err, "Error removing directory") } }() @@ -316,10 +316,10 @@ func TestAppImportExport(t *testing.T) { defer func() { if err := newDB.Close(); err != nil { - t.Errorf("Error closing new database: %v", err) + require.NoError(t, err, "Error closing new database") } if err := os.RemoveAll(newDir); err != nil { - t.Errorf("Error removing directory %s: %v", newDir, err) + require.NoError(t, err, "Error removing directory") } }() @@ -342,23 +342,24 @@ func TestAppImportExport(t *testing.T) { if !strings.Contains(err, "validator set is empty after InitGenesis") { panic(r) } - logger.Info("Skipping simulation as all validators have been unbonded") - logger.Info("err", err, "stacktrace", string(debug.Stack())) + t.Log("Skipping simulation as all validators have been unbonded") + t.Log("err", err, "stacktrace", string(debug.Stack())) } }() - ctxA := simApp.NewContext(true, tmproto.Header{ + // Create context for the old and the new sim app, which can be used to compare keys + ctxSimApp := simApp.NewContext(true, tmproto.Header{ Height: simApp.LastBlockHeight(), ChainID: SimAppChainID, }).WithChainID(SimAppChainID) - ctxB := newSimApp.NewContext(true, tmproto.Header{ + ctxNewSimApp := newSimApp.NewContext(true, tmproto.Header{ Height: simApp.LastBlockHeight(), ChainID: SimAppChainID, }).WithChainID(SimAppChainID) // Use genesis state from the first app to initialize the second app - newSimApp.ModuleManager().InitGenesis(ctxB, newSimApp.AppCodec(), genesisState) - newSimApp.StoreConsensusParams(ctxB, exported.ConsensusParams) + newSimApp.ModuleManager().InitGenesis(ctxNewSimApp, newSimApp.AppCodec(), genesisState) + newSimApp.StoreConsensusParams(ctxNewSimApp, exported.ConsensusParams) t.Log("comparing stores") // The ordering of the keys is not important, we compare the same prefix for both simulations @@ -381,8 +382,8 @@ func TestAppImportExport(t *testing.T) { } for _, skp := range storeKeysPrefixes { - storeA := ctxA.KVStore(skp.A) - storeB := ctxB.KVStore(skp.B) + storeA := ctxSimApp.KVStore(skp.A) + storeB := ctxNewSimApp.KVStore(skp.B) failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes) require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare") @@ -423,10 +424,10 @@ func TestAppSimulationAfterImport(t *testing.T) { defer func() { if err := db.Close(); err != nil { - t.Errorf("Error closing new database: %v", err) + require.NoError(t, err, "Error closing new database") } if err := os.RemoveAll(dir); err != nil { - t.Errorf("Error removing directory %s: %v", dir, err) + require.NoError(t, err, "Error removing directory") } }() @@ -485,10 +486,10 @@ func TestAppSimulationAfterImport(t *testing.T) { defer func() { if err := newDB.Close(); err != nil { - t.Errorf("Error closing new database: %v", err) + require.NoError(t, err, "Error closing new database") } if err := os.RemoveAll(newDir); err != nil { - t.Errorf("Error removing directory %s: %v", newDir, err) + require.NoError(t, err, "Error removing directory") } }() From d18978bfcd89d73697099fd758f9af7c032dddf7 Mon Sep 17 00:00:00 2001 From: Julian Rubino Date: Thu, 24 Oct 2024 14:58:25 -0300 Subject: [PATCH 41/59] Add runs on to matrix conditional job --- .github/workflows/sim.yaml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index c9b88fdeec..906803782d 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -40,22 +40,19 @@ jobs: simulation-tests: needs: matrix-conditionals + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: include: - make-target: "test-sim-nondeterminism" - runs-on: ubuntu-22.04 - run: ${{ needs.matrix-conditionals.outputs.SIM_TEST_NOND == 'true' }} + condition: ${{ needs.matrix-conditionals.outputs.SIM_TEST_NOND == 'true' }} - make-target: "test-sim-fullappsimulation" - runs-on: ubuntu-22.04 - run: ${{ needs.matrix-conditionals.outputs.SIM_TEST_FULL == 'true' }} + condition: ${{ needs.matrix-conditionals.outputs.SIM_TEST_FULL == 'true' }} - make-target: "test-sim-import-export" - runs-on: ubuntu-22.04 - run: ${{ needs.matrix-conditionals.outputs.SIM_TEST_IMPORT_EXPORT == 'true' }} + condition: ${{ needs.matrix-conditionals.outputs.SIM_TEST_IMPORT_EXPORT == 'true' }} - make-target: "test-sim-after-import" - runs-on: ubuntu-22.04 - run: ${{ needs.matrix-conditionals.outputs.SIM_TEST_AFTER_IMPORT == 'true' }} + condition: ${{ needs.matrix-conditionals.outputs.SIM_TEST_AFTER_IMPORT == 'true' }} name: ${{ matrix.make-target }} steps: - name: Checkout code @@ -70,6 +67,7 @@ jobs: run: make runsim - name: Run ${{ matrix.make-target }} + if: ${{ matrix.condition }} run: | make ${{ matrix.make-target }} From 195bc8de4d1d8d16f9f2e33cab7c2b0e7e455ead Mon Sep 17 00:00:00 2001 From: Julian Rubino Date: Thu, 24 Oct 2024 14:59:55 -0300 Subject: [PATCH 42/59] add default make-targets --- .github/workflows/sim.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index 906803782d..075e034016 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -32,7 +32,11 @@ jobs: uses: actions/github-script@v7 with: script: | - const makeTargets = context.payload.inputs['make-targets'].split(','); + const makeTargetsInput = context.payload.inputs ? context.payload.inputs['make-targets'] : null; + const defaultTargets = ['test-sim-nondeterminism', 'test-sim-fullappsimulation', 'test-sim-import-export', 'test-sim-after-import']; + + const makeTargets = makeTargetsInput ? makeTargetsInput.split(',') : defaultTargets; + core.setOutput('SIM_TEST_NOND', makeTargets.includes('test-sim-nondeterminism')); core.setOutput('SIM_TEST_FULL', makeTargets.includes('test-sim-fullappsimulation')); core.setOutput('SIM_TEST_IMPORT_EXPORT', makeTargets.includes('test-sim-import-export')); From 7458f94686c18b8e3ced2c9c6b76bb82903dc792 Mon Sep 17 00:00:00 2001 From: Julian Rubino Date: Thu, 24 Oct 2024 15:05:18 -0300 Subject: [PATCH 43/59] bump go --- .github/workflows/sim.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index 075e034016..dee2d0eb87 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -65,7 +65,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.20' + go-version: '1.21' - name: Install dependencies run: make runsim From 399569dab19583174e7cea4561fa0d5d800731e6 Mon Sep 17 00:00:00 2001 From: Julian Rubino Date: Fri, 25 Oct 2024 13:20:13 +0900 Subject: [PATCH 44/59] Update .github/workflows/sim.yaml workflow name Co-authored-by: Alex Gartner --- .github/workflows/sim.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index dee2d0eb87..1d766a2972 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -1,4 +1,4 @@ -name: Simulation Tests Workflow +name: sim on: push: From cf60f5a1c3a401b278facc8c8ef6f075e654c389 Mon Sep 17 00:00:00 2001 From: Julian Rubino Date: Fri, 25 Oct 2024 13:20:47 +0900 Subject: [PATCH 45/59] Delete main branch from sim test workflow --- .github/workflows/sim.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index 1d766a2972..953125693b 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -3,7 +3,6 @@ name: sim on: push: branches: - - main - develop pull_request: schedule: From 5c682e95e577886eca56b5a271f6f3b67d1d4584 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 25 Oct 2024 12:14:11 -0400 Subject: [PATCH 46/59] improve formatting for simulation.md --- docs/development/SIMULATION_TESTING.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/development/SIMULATION_TESTING.md b/docs/development/SIMULATION_TESTING.md index 05eb0d4b98..fce2e78f9b 100644 --- a/docs/development/SIMULATION_TESTING.md +++ b/docs/development/SIMULATION_TESTING.md @@ -1,8 +1,8 @@ # Zetachain simulation testing ## Overview The blockchain simulation tests how the blockchain application would behave under real life circumstances by generating -and sending randomized messages.The goal of this is to detect and debug failures that could halt a live chain,by -providing logs and statistics about the operations run by the simulator as well as exporting the latest application +and sending randomized messages.The goal of this is to detect and debug failures that could halt a live chain by +providing logs and statistics about the operations run by the simulator as well as exporting the latest application state. ## Simulation tests @@ -10,7 +10,7 @@ state. ### Nondeterminism test Nondeterminism test runs a full application simulation , and produces multiple blocks as per the config It checks the determinism of the application by comparing the apphash at the end of each run to other runs -The test certifies that , for the same set of operations ( irrespective of what the operations are ), we +The test certifies that, for the same set of operations (regardless of what the operations are), we would reach the same final state if the initial state is the same ```bash make test-sim-nondeterminism @@ -18,7 +18,7 @@ make test-sim-nondeterminism ### Full application simulation test Full application runs a full app simulation test with the provided configuration. -At the end of the run it tries to export the genesis state to make sure the export works. +At the end of the run, it tries to export the genesis state to make sure the export works. ```bash make test-sim-full-app ``` @@ -27,7 +27,7 @@ make test-sim-full-app The import export simulation test runs a full application simulation and exports the application state at the end of the run. This state is then imported into a new simulation. -At the end of the run we compare the keys for the application state for both the simulations +At the end of the run, we compare the keys for the application state for both the simulations to make sure they are the same. ```bash make test-sim-import-export @@ -41,28 +41,28 @@ make test-sim-after-import ### Multi seed long test Multi seed long test runs a full application simulation with multiple seeds and multiple blocks. -This runs the test for a longer duration compared to the multi seed short test +This runs the test for a longer duration compared to the multi seed short test. ```bash make test-sim-multi-seed-long ``` ### Multi seed short test Multi seed short test runs a full application simulation with multiple seeds and multiple blocks. -This runs the test for a shorter duration compared to the multi seed long test +This runs the test for a shorter duration compared to the multi seed long test. ```bash make test-sim-multi-seed-short ``` ### Import Export long test This test runs the import export simulation test for a longer duration. -It uses the runsim tool to run the same test in parallel threads +It uses the `runsim` tool to run the same test in parallel threads. ```bash make test-sim-import-export-long ``` ### Import and run simulation test long This test runs the import and run simulation test for a longer duration. -It uses the runsim tool to run the same test in parallel threads +It uses the `runsim` tool to run the same test in parallel threads. ```bash make test-sim-after-import-long ``` From 06c5d7531f9afc9e523bfafdb623a9a06914bbca Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 28 Oct 2024 20:11:23 -0400 Subject: [PATCH 47/59] move simulation tests to root directory --- .github/workflows/sim.yaml | 4 +- Makefile | 2 +- .../sim/sim_config.go | 0 .../sim/sim_state.go | 0 .../sim/sim_utils.go | 0 {tests/simulation => simulation}/sim_test.go | 109 +++++++++--------- 6 files changed, 58 insertions(+), 57 deletions(-) rename {tests/simulation => simulation}/sim/sim_config.go (100%) rename {tests/simulation => simulation}/sim/sim_state.go (100%) rename {tests/simulation => simulation}/sim/sim_utils.go (100%) rename {tests/simulation => simulation}/sim_test.go (87%) diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index 953125693b..98faf38233 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -12,7 +12,7 @@ on: make-targets: description: 'Comma separated list of make targets to run (e.g., test-sim-nondeterminism, test-sim-fullappsimulation)' required: true - default: '' + default: 'test-sim-nondeterminism' concurrency: group: simulation-${{ github.head_ref || github.sha }} @@ -64,7 +64,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.21' + go-version: '1.22' - name: Install dependencies run: make runsim diff --git a/Makefile b/Makefile index 8bbcf7217a..46306b4c4d 100644 --- a/Makefile +++ b/Makefile @@ -360,7 +360,7 @@ start-upgrade-import-mainnet-test: zetanode-upgrade ############################################################################### BINDIR ?= $(GOPATH)/bin -SIMAPP = ./tests/simulation +SIMAPP = ./simulation # Run sim is a cosmos tool which helps us to run multiple simulations in parallel. diff --git a/tests/simulation/sim/sim_config.go b/simulation/sim/sim_config.go similarity index 100% rename from tests/simulation/sim/sim_config.go rename to simulation/sim/sim_config.go diff --git a/tests/simulation/sim/sim_state.go b/simulation/sim/sim_state.go similarity index 100% rename from tests/simulation/sim/sim_state.go rename to simulation/sim/sim_state.go diff --git a/tests/simulation/sim/sim_utils.go b/simulation/sim/sim_utils.go similarity index 100% rename from tests/simulation/sim/sim_utils.go rename to simulation/sim/sim_utils.go diff --git a/tests/simulation/sim_test.go b/simulation/sim_test.go similarity index 87% rename from tests/simulation/sim_test.go rename to simulation/sim_test.go index d8335fb8a9..3f8a73fa07 100644 --- a/tests/simulation/sim_test.go +++ b/simulation/sim_test.go @@ -22,12 +22,11 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" evmtypes "github.com/zeta-chain/ethermint/x/evm/types" + "github.com/zeta-chain/node/simulation/sim" + "github.com/cosmos/cosmos-sdk/store" "github.com/stretchr/testify/require" "github.com/zeta-chain/node/app" - simutils "github.com/zeta-chain/node/tests/simulation/sim" - - "github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client/flags" @@ -41,7 +40,7 @@ import ( // AppChainID hardcoded chainID for simulation func init() { - simutils.GetSimulatorFlags() + sim.GetSimulatorFlags() } type StoreKeysPrefixes struct { @@ -70,11 +69,11 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { // The following test certifies that , for the same set of operations ( irrespective of what the operations are ) , // we would reach the same final state if the initial state is the same func TestAppStateDeterminism(t *testing.T) { - if !simutils.FlagEnabledValue { + if !sim.FlagEnabledValue { t.Skip("skipping application simulation") } - config := simutils.NewConfigFromFlags() + config := sim.NewConfigFromFlags() config.InitialBlockHeight = 1 config.ExportParamsPath = "" @@ -95,7 +94,7 @@ func TestAppStateDeterminism(t *testing.T) { appHashList := make([]json.RawMessage, numTimesToRunPerSeed) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue t.Log("Running tests for numSeeds: ", numSeeds, " numTimesToRunPerSeed: ", numTimesToRunPerSeed) @@ -109,13 +108,13 @@ func TestAppStateDeterminism(t *testing.T) { config, SimDBBackend, SimDBName, - simutils.FlagVerboseValue, - simutils.FlagEnabledValue, + sim.FlagVerboseValue, + sim.FlagEnabledValue, ) require.NoError(t, err) appOptions[flags.FlagHome] = dir - simApp, err := simutils.NewSimApp( + simApp, err := sim.NewSimApp( logger, db, appOptions, @@ -135,7 +134,7 @@ func TestAppStateDeterminism(t *testing.T) { t, os.Stdout, simApp.BaseApp, - simutils.AppStateFn( + sim.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -148,14 +147,16 @@ func TestAppStateDeterminism(t *testing.T) { ) require.NoError(t, err) - simutils.PrintStats(db) + sim.PrintStats(db) appHash := simApp.LastCommitID().Hash appHashList[j] = appHash // Clean up resources - require.NoError(t, db.Close()) - require.NoError(t, os.RemoveAll(dir)) + t.Cleanup(func() { + require.NoError(t, db.Close()) + require.NoError(t, os.RemoveAll(dir)) + }) if j != 0 { require.Equal( @@ -178,7 +179,7 @@ func TestAppStateDeterminism(t *testing.T) { // At the end of the run it tries to export the genesis state to make sure the export works. func TestFullAppSimulation(t *testing.T) { - config := simutils.NewConfigFromFlags() + config := sim.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas @@ -188,27 +189,27 @@ func TestFullAppSimulation(t *testing.T) { config, SimDBBackend, SimDBName, - simutils.FlagVerboseValue, - simutils.FlagEnabledValue, + sim.FlagVerboseValue, + sim.FlagEnabledValue, ) if skip { t.Skip("skipping application simulation") } require.NoError(t, err, "simulation setup failed") - defer func() { + t.Cleanup(func() { if err := db.Close(); err != nil { require.NoError(t, err, "Error closing new database") } if err := os.RemoveAll(dir); err != nil { require.NoError(t, err, "Error removing directory") } - }() + }) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := simutils.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := sim.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) blockedAddresses := simApp.ModuleAccountAddrs() @@ -216,7 +217,7 @@ func TestFullAppSimulation(t *testing.T) { t, os.Stdout, simApp.BaseApp, - simutils.AppStateFn( + sim.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -237,11 +238,11 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, err) } - simutils.PrintStats(db) + sim.PrintStats(db) } func TestAppImportExport(t *testing.T) { - config := simutils.NewConfigFromFlags() + config := sim.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas @@ -251,27 +252,27 @@ func TestAppImportExport(t *testing.T) { config, SimDBBackend, SimDBName, - simutils.FlagVerboseValue, - simutils.FlagEnabledValue, + sim.FlagVerboseValue, + sim.FlagEnabledValue, ) if skip { t.Skip("skipping application simulation") } require.NoError(t, err, "simulation setup failed") - defer func() { + t.Cleanup(func() { if err := db.Close(); err != nil { require.NoError(t, err, "Error closing new database") } if err := os.RemoveAll(dir); err != nil { require.NoError(t, err, "Error removing directory") } - }() + }) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := simutils.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := sim.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) // Run randomized simulation @@ -280,7 +281,7 @@ func TestAppImportExport(t *testing.T) { t, os.Stdout, simApp.BaseApp, - simutils.AppStateFn( + sim.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -293,10 +294,10 @@ func TestAppImportExport(t *testing.T) { ) require.NoError(t, simErr) - err = simutils.CheckExportSimulation(simApp, config, simParams) + err = sim.CheckExportSimulation(simApp, config, simParams) require.NoError(t, err) - simutils.PrintStats(db) + sim.PrintStats(db) t.Log("exporting genesis") // export state and simParams @@ -308,22 +309,22 @@ func TestAppImportExport(t *testing.T) { config, SimDBBackend+"_new", SimDBName+"_new", - simutils.FlagVerboseValue, - simutils.FlagEnabledValue, + sim.FlagVerboseValue, + sim.FlagEnabledValue, ) require.NoError(t, err, "simulation setup failed") - defer func() { + t.Cleanup(func() { if err := newDB.Close(); err != nil { require.NoError(t, err, "Error closing new database") } if err := os.RemoveAll(newDir); err != nil { require.NoError(t, err, "Error removing directory") } - }() + }) - newSimApp, err := simutils.NewSimApp( + newSimApp, err := sim.NewSimApp( logger, newDB, appOptions, @@ -404,7 +405,7 @@ func TestAppImportExport(t *testing.T) { } func TestAppSimulationAfterImport(t *testing.T) { - config := simutils.NewConfigFromFlags() + config := sim.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas @@ -414,27 +415,27 @@ func TestAppSimulationAfterImport(t *testing.T) { config, SimDBBackend, SimDBName, - simutils.FlagVerboseValue, - simutils.FlagEnabledValue, + sim.FlagVerboseValue, + sim.FlagEnabledValue, ) if skip { t.Skip("skipping application simulation") } require.NoError(t, err, "simulation setup failed") - defer func() { + t.Cleanup(func() { if err := db.Close(); err != nil { require.NoError(t, err, "Error closing new database") } if err := os.RemoveAll(dir); err != nil { require.NoError(t, err, "Error removing directory") } - }() + }) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = simutils.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := simutils.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := sim.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) // Run randomized simulation @@ -443,7 +444,7 @@ func TestAppSimulationAfterImport(t *testing.T) { t, os.Stdout, simApp.BaseApp, - simutils.AppStateFn( + sim.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -456,10 +457,10 @@ func TestAppSimulationAfterImport(t *testing.T) { ) require.NoError(t, simErr) - err = simutils.CheckExportSimulation(simApp, config, simParams) + err = sim.CheckExportSimulation(simApp, config, simParams) require.NoError(t, err) - simutils.PrintStats(db) + sim.PrintStats(db) if stopEarly { t.Log("can't export or import a zero-validator genesis, exiting test") @@ -478,22 +479,22 @@ func TestAppSimulationAfterImport(t *testing.T) { config, SimDBBackend+"_new", SimDBName+"_new", - simutils.FlagVerboseValue, - simutils.FlagEnabledValue, + sim.FlagVerboseValue, + sim.FlagEnabledValue, ) require.NoError(t, err, "simulation setup failed") - defer func() { + t.Cleanup(func() { if err := newDB.Close(); err != nil { require.NoError(t, err, "Error closing new database") } if err := os.RemoveAll(newDir); err != nil { require.NoError(t, err, "Error removing directory") } - }() + }) - newSimApp, err := simutils.NewSimApp( + newSimApp, err := sim.NewSimApp( logger, newDB, appOptions, @@ -511,7 +512,7 @@ func TestAppSimulationAfterImport(t *testing.T) { t, os.Stdout, newSimApp.BaseApp, - simutils.AppStateFn( + sim.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), From d27702d20e7768928650abe5fe003cbd71a0268c Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 28 Oct 2024 20:17:00 -0400 Subject: [PATCH 48/59] remove panic for Import Export Test --- simulation/sim_test.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/simulation/sim_test.go b/simulation/sim_test.go index 3f8a73fa07..0bc068ae7a 100644 --- a/simulation/sim_test.go +++ b/simulation/sim_test.go @@ -6,7 +6,6 @@ import ( "math/rand" "os" "runtime/debug" - "strings" "testing" abci "github.com/cometbft/cometbft/abci/types" @@ -340,9 +339,7 @@ func TestAppImportExport(t *testing.T) { defer func() { if r := recover(); r != nil { err := fmt.Sprintf("%v", r) - if !strings.Contains(err, "validator set is empty after InitGenesis") { - panic(r) - } + require.Contains(t, err, "validator set is empty after InitGenesis", "unexpected error: %v", r) t.Log("Skipping simulation as all validators have been unbonded") t.Log("err", err, "stacktrace", string(debug.Stack())) } From 5132383d40186122ca51f6bf94c04018d7f09435 Mon Sep 17 00:00:00 2001 From: Julian Rubino Date: Tue, 29 Oct 2024 11:26:18 -0300 Subject: [PATCH 49/59] Trigger Sim Tests on Labeled PRs or when any file from x/**/* is changed --- .github/workflows/sim.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index dee2d0eb87..92bd0bad59 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -6,6 +6,7 @@ on: - main - develop pull_request: + types: [opened, synchronize, labeled] schedule: - cron: "0 6 * * *" workflow_dispatch: @@ -20,7 +21,23 @@ concurrency: cancel-in-progress: true jobs: + changed-files: + runs-on: ubuntu-latest + outputs: + modified_files: ${{ steps.changes.outputs.modified_files }} + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Get changed files in x directory + id: changes + run: | + echo "::set-output name=modified_files::$(git diff --name-only --diff-filter=ACMRT ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | grep '^x/' | xargs)" + matrix-conditionals: + needs: changed-files + if: | + contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files runs-on: ubuntu-22.04 outputs: SIM_TEST_NOND: ${{ steps.matrix-conditionals.outputs.SIM_TEST_NOND }} @@ -43,6 +60,9 @@ jobs: core.setOutput('SIM_TEST_AFTER_IMPORT', makeTargets.includes('test-sim-after-import')); simulation-tests: + needs: changed-files + if: | + contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files needs: matrix-conditionals runs-on: ubuntu-22.04 strategy: @@ -76,6 +96,9 @@ jobs: make ${{ matrix.make-target }} sim-ok: + needs: changed-files + if: | + contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files runs-on: ubuntu-22.04 needs: - matrix-conditionals From f2341e8e949ff7a0583e5258ddea602076ac43ec Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 29 Oct 2024 11:45:02 -0400 Subject: [PATCH 50/59] update sim.yaml --- .github/workflows/sim.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index dcbdef675b..ccd5752302 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -62,7 +62,6 @@ jobs: needs: changed-files if: | contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files - needs: matrix-conditionals runs-on: ubuntu-22.04 strategy: fail-fast: false @@ -97,12 +96,8 @@ jobs: sim-ok: needs: changed-files if: | - contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files + contains(github.event.pull_request.labels.*.name, 'simulation_tests') || needs.changed-files.outputs.modified_files runs-on: ubuntu-22.04 - needs: - - matrix-conditionals - - simulation-tests - if: always() steps: - name: Aggregate Results run: | From 29f04e8cac5b5eaf7141630027f320c4bbed20e0 Mon Sep 17 00:00:00 2001 From: Julian Rubino Date: Wed, 30 Oct 2024 00:50:57 +0900 Subject: [PATCH 51/59] Update sim.yaml jobs needs --- .github/workflows/sim.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index ccd5752302..0585398d24 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -59,7 +59,8 @@ jobs: core.setOutput('SIM_TEST_AFTER_IMPORT', makeTargets.includes('test-sim-after-import')); simulation-tests: - needs: changed-files + needs: + - matrix-conditionals if: | contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files runs-on: ubuntu-22.04 @@ -94,7 +95,8 @@ jobs: make ${{ matrix.make-target }} sim-ok: - needs: changed-files + needs: + - simulation-tests if: | contains(github.event.pull_request.labels.*.name, 'simulation_tests') || needs.changed-files.outputs.modified_files runs-on: ubuntu-22.04 From 2fdb90bde8b7f846a9bbea63547278c34f1379a3 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 29 Oct 2024 12:00:54 -0400 Subject: [PATCH 52/59] update sim.yaml --- .github/workflows/sim.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index ccd5752302..9f6e10e1d3 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -36,7 +36,7 @@ jobs: matrix-conditionals: needs: changed-files if: | - contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files + contains(github.event.pull_request.labels.*.name, 'simulation_tests') || needs.changed-files.outputs.modified_files runs-on: ubuntu-22.04 outputs: SIM_TEST_NOND: ${{ steps.matrix-conditionals.outputs.SIM_TEST_NOND }} @@ -61,7 +61,7 @@ jobs: simulation-tests: needs: changed-files if: | - contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files + contains(github.event.pull_request.labels.*.name, 'simulation_tests') || needs.changed-files.outputs.modified_files runs-on: ubuntu-22.04 strategy: fail-fast: false From eaa150db65e951fd2c7df757de8f40650dbc6038 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 29 Oct 2024 12:10:49 -0400 Subject: [PATCH 53/59] update codecov.yml --- codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecov.yml b/codecov.yml index 49cd96e8a0..7778c1672d 100644 --- a/codecov.yml +++ b/codecov.yml @@ -81,4 +81,4 @@ ignore: - "precompiles/**/*.json" - "precompiles/**/*.sol" - "precompiles/**/*.gen.go" - - "tests/simulation/**/*" + - "simulation/**/*" From 476a62357e85afac6c6d5178cecd1fe2c50835ad Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 30 Oct 2024 11:40:54 -0400 Subject: [PATCH 54/59] fixed some comments --- Makefile | 4 ++-- app/export.go | 12 +++++++++--- docs/development/SIMULATION_TESTING.md | 15 ++++++++++++--- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 46306b4c4d..ace44f1b6e 100644 --- a/Makefile +++ b/Makefile @@ -408,11 +408,11 @@ test-sim-multi-seed-short: runsim test-sim-import-export-long: runsim @echo "Running application import/export simulation. This may take several minutes" - @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppImportExport + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestAppImportExport test-sim-after-import-long: runsim @echo "Running application simulation-after-import. This may take several minute" - @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppSimulationAfterImport + @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestAppSimulationAfterImport .PHONY: \ test-sim-nondeterminism \ diff --git a/app/export.go b/app/export.go index 50287e204d..822e019b24 100644 --- a/app/export.go +++ b/app/export.go @@ -2,11 +2,13 @@ package app import ( "encoding/json" + "errors" "log" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -75,7 +77,10 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []str // withdraw all validator commission app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { - _, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator()) + _, err := app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator()) + if !errors.Is(err, distributiontypes.ErrNoValidatorCommission) && err != nil { + panic(err) + } return false }) @@ -160,11 +165,12 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []str for ; iter.Valid(); iter.Next() { key := iter.Key() - if len(key) <= 2 { + keyPrefixLength := 2 + if len(key) <= keyPrefixLength { app.Logger().Error("unexpected key in staking store", "key", key) continue } - addr := sdk.ValAddress(key[2:]) + addr := sdk.ValAddress(key[keyPrefixLength:]) validator, found := app.StakingKeeper.GetValidator(ctx, addr) if !found { panic("expected validator, not found") diff --git a/docs/development/SIMULATION_TESTING.md b/docs/development/SIMULATION_TESTING.md index fce2e78f9b..e6bb2f2ca7 100644 --- a/docs/development/SIMULATION_TESTING.md +++ b/docs/development/SIMULATION_TESTING.md @@ -12,6 +12,7 @@ Nondeterminism test runs a full application simulation , and produces multiple b It checks the determinism of the application by comparing the apphash at the end of each run to other runs The test certifies that, for the same set of operations (regardless of what the operations are), we would reach the same final state if the initial state is the same +Approximate run time is 2 minutes. ```bash make test-sim-nondeterminism ``` @@ -19,6 +20,7 @@ make test-sim-nondeterminism ### Full application simulation test Full application runs a full app simulation test with the provided configuration. At the end of the run, it tries to export the genesis state to make sure the export works. +Approximate run time is 2 minutes. ```bash make test-sim-full-app ``` @@ -29,26 +31,31 @@ and exports the application state at the end of the run. This state is then imported into a new simulation. At the end of the run, we compare the keys for the application state for both the simulations to make sure they are the same. +Approximate run time is 2 minutes. ```bash make test-sim-import-export ``` ### Import and run simulation test This simulation test exports the application state at the end of the run and imports it into a new simulation. +Approximate run time is 2 minutes. ```bash make test-sim-after-import ``` ### Multi seed long test Multi seed long test runs a full application simulation with multiple seeds and multiple blocks. -This runs the test for a longer duration compared to the multi seed short test. +It uses the `runsim` tool to run the same test in parallel threads. +Approximate run time is 30 minutes. ```bash make test-sim-multi-seed-long ``` ### Multi seed short test -Multi seed short test runs a full application simulation with multiple seeds and multiple blocks. -This runs the test for a shorter duration compared to the multi seed long test. +Multi seed short test runs a full application simulation with multiple seeds and multiple blocks. +It uses the `runsim` tool to run the same test in parallel threads. +This test is a shorter version of the Multi seed long test. +Approximate run time is 10 minutes. ```bash make test-sim-multi-seed-short ``` @@ -56,6 +63,7 @@ make test-sim-multi-seed-short ### Import Export long test This test runs the import export simulation test for a longer duration. It uses the `runsim` tool to run the same test in parallel threads. +Approximate run time is 30 minutes. ```bash make test-sim-import-export-long ``` @@ -63,6 +71,7 @@ make test-sim-import-export-long ### Import and run simulation test long This test runs the import and run simulation test for a longer duration. It uses the `runsim` tool to run the same test in parallel threads. +Approximate run time is 30 minutes. ```bash make test-sim-after-import-long ``` From ded60cb9682ed3c1966c8e744fc7b20250e9777a Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 30 Oct 2024 12:23:14 -0400 Subject: [PATCH 55/59] remove directory sim --- simulation/{sim/sim_config.go => config.go} | 2 +- .../{sim/sim_state.go => simulation.go} | 2 +- .../{sim_test.go => simulation_test.go} | 85 +++++++++---------- simulation/{sim/sim_utils.go => utils.go} | 2 +- 4 files changed, 45 insertions(+), 46 deletions(-) rename simulation/{sim/sim_config.go => config.go} (99%) rename simulation/{sim/sim_state.go => simulation.go} (99%) rename simulation/{sim_test.go => simulation_test.go} (88%) rename simulation/{sim/sim_utils.go => utils.go} (99%) diff --git a/simulation/sim/sim_config.go b/simulation/config.go similarity index 99% rename from simulation/sim/sim_config.go rename to simulation/config.go index 8a6c281db8..254365c856 100644 --- a/simulation/sim/sim_config.go +++ b/simulation/config.go @@ -1,4 +1,4 @@ -package sim +package simulation import ( "flag" diff --git a/simulation/sim/sim_state.go b/simulation/simulation.go similarity index 99% rename from simulation/sim/sim_state.go rename to simulation/simulation.go index c8df9f4f31..540cd0aca7 100644 --- a/simulation/sim/sim_state.go +++ b/simulation/simulation.go @@ -1,4 +1,4 @@ -package sim +package simulation import ( "encoding/json" diff --git a/simulation/sim_test.go b/simulation/simulation_test.go similarity index 88% rename from simulation/sim_test.go rename to simulation/simulation_test.go index 0bc068ae7a..ee6a036338 100644 --- a/simulation/sim_test.go +++ b/simulation/simulation_test.go @@ -10,6 +10,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/cosmos/cosmos-sdk/store" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -20,12 +21,10 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - evmtypes "github.com/zeta-chain/ethermint/x/evm/types" - "github.com/zeta-chain/node/simulation/sim" - - "github.com/cosmos/cosmos-sdk/store" "github.com/stretchr/testify/require" + evmtypes "github.com/zeta-chain/ethermint/x/evm/types" "github.com/zeta-chain/node/app" + simulation2 "github.com/zeta-chain/node/simulation" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client/flags" @@ -39,7 +38,7 @@ import ( // AppChainID hardcoded chainID for simulation func init() { - sim.GetSimulatorFlags() + simulation2.GetSimulatorFlags() } type StoreKeysPrefixes struct { @@ -68,11 +67,11 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { // The following test certifies that , for the same set of operations ( irrespective of what the operations are ) , // we would reach the same final state if the initial state is the same func TestAppStateDeterminism(t *testing.T) { - if !sim.FlagEnabledValue { + if !simulation2.FlagEnabledValue { t.Skip("skipping application simulation") } - config := sim.NewConfigFromFlags() + config := simulation2.NewConfigFromFlags() config.InitialBlockHeight = 1 config.ExportParamsPath = "" @@ -93,7 +92,7 @@ func TestAppStateDeterminism(t *testing.T) { appHashList := make([]json.RawMessage, numTimesToRunPerSeed) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = simulation2.FlagPeriodValue t.Log("Running tests for numSeeds: ", numSeeds, " numTimesToRunPerSeed: ", numTimesToRunPerSeed) @@ -107,13 +106,13 @@ func TestAppStateDeterminism(t *testing.T) { config, SimDBBackend, SimDBName, - sim.FlagVerboseValue, - sim.FlagEnabledValue, + simulation2.FlagVerboseValue, + simulation2.FlagEnabledValue, ) require.NoError(t, err) appOptions[flags.FlagHome] = dir - simApp, err := sim.NewSimApp( + simApp, err := simulation2.NewSimApp( logger, db, appOptions, @@ -133,7 +132,7 @@ func TestAppStateDeterminism(t *testing.T) { t, os.Stdout, simApp.BaseApp, - sim.AppStateFn( + simulation2.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -146,7 +145,7 @@ func TestAppStateDeterminism(t *testing.T) { ) require.NoError(t, err) - sim.PrintStats(db) + simulation2.PrintStats(db) appHash := simApp.LastCommitID().Hash appHashList[j] = appHash @@ -178,7 +177,7 @@ func TestAppStateDeterminism(t *testing.T) { // At the end of the run it tries to export the genesis state to make sure the export works. func TestFullAppSimulation(t *testing.T) { - config := sim.NewConfigFromFlags() + config := simulation2.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas @@ -188,8 +187,8 @@ func TestFullAppSimulation(t *testing.T) { config, SimDBBackend, SimDBName, - sim.FlagVerboseValue, - sim.FlagEnabledValue, + simulation2.FlagVerboseValue, + simulation2.FlagEnabledValue, ) if skip { t.Skip("skipping application simulation") @@ -205,10 +204,10 @@ func TestFullAppSimulation(t *testing.T) { } }) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = simulation2.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := sim.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := simulation2.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) blockedAddresses := simApp.ModuleAccountAddrs() @@ -216,7 +215,7 @@ func TestFullAppSimulation(t *testing.T) { t, os.Stdout, simApp.BaseApp, - sim.AppStateFn( + simulation2.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -237,11 +236,11 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, err) } - sim.PrintStats(db) + simulation2.PrintStats(db) } func TestAppImportExport(t *testing.T) { - config := sim.NewConfigFromFlags() + config := simulation2.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas @@ -251,8 +250,8 @@ func TestAppImportExport(t *testing.T) { config, SimDBBackend, SimDBName, - sim.FlagVerboseValue, - sim.FlagEnabledValue, + simulation2.FlagVerboseValue, + simulation2.FlagEnabledValue, ) if skip { t.Skip("skipping application simulation") @@ -269,9 +268,9 @@ func TestAppImportExport(t *testing.T) { }) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = simulation2.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := sim.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := simulation2.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) // Run randomized simulation @@ -280,7 +279,7 @@ func TestAppImportExport(t *testing.T) { t, os.Stdout, simApp.BaseApp, - sim.AppStateFn( + simulation2.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -293,10 +292,10 @@ func TestAppImportExport(t *testing.T) { ) require.NoError(t, simErr) - err = sim.CheckExportSimulation(simApp, config, simParams) + err = simulation2.CheckExportSimulation(simApp, config, simParams) require.NoError(t, err) - sim.PrintStats(db) + simulation2.PrintStats(db) t.Log("exporting genesis") // export state and simParams @@ -308,8 +307,8 @@ func TestAppImportExport(t *testing.T) { config, SimDBBackend+"_new", SimDBName+"_new", - sim.FlagVerboseValue, - sim.FlagEnabledValue, + simulation2.FlagVerboseValue, + simulation2.FlagEnabledValue, ) require.NoError(t, err, "simulation setup failed") @@ -323,7 +322,7 @@ func TestAppImportExport(t *testing.T) { } }) - newSimApp, err := sim.NewSimApp( + newSimApp, err := simulation2.NewSimApp( logger, newDB, appOptions, @@ -402,7 +401,7 @@ func TestAppImportExport(t *testing.T) { } func TestAppSimulationAfterImport(t *testing.T) { - config := sim.NewConfigFromFlags() + config := simulation2.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas @@ -412,8 +411,8 @@ func TestAppSimulationAfterImport(t *testing.T) { config, SimDBBackend, SimDBName, - sim.FlagVerboseValue, - sim.FlagEnabledValue, + simulation2.FlagVerboseValue, + simulation2.FlagEnabledValue, ) if skip { t.Skip("skipping application simulation") @@ -430,9 +429,9 @@ func TestAppSimulationAfterImport(t *testing.T) { }) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = sim.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = simulation2.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := sim.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := simulation2.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) // Run randomized simulation @@ -441,7 +440,7 @@ func TestAppSimulationAfterImport(t *testing.T) { t, os.Stdout, simApp.BaseApp, - sim.AppStateFn( + simulation2.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -454,10 +453,10 @@ func TestAppSimulationAfterImport(t *testing.T) { ) require.NoError(t, simErr) - err = sim.CheckExportSimulation(simApp, config, simParams) + err = simulation2.CheckExportSimulation(simApp, config, simParams) require.NoError(t, err) - sim.PrintStats(db) + simulation2.PrintStats(db) if stopEarly { t.Log("can't export or import a zero-validator genesis, exiting test") @@ -476,8 +475,8 @@ func TestAppSimulationAfterImport(t *testing.T) { config, SimDBBackend+"_new", SimDBName+"_new", - sim.FlagVerboseValue, - sim.FlagEnabledValue, + simulation2.FlagVerboseValue, + simulation2.FlagEnabledValue, ) require.NoError(t, err, "simulation setup failed") @@ -491,7 +490,7 @@ func TestAppSimulationAfterImport(t *testing.T) { } }) - newSimApp, err := sim.NewSimApp( + newSimApp, err := simulation2.NewSimApp( logger, newDB, appOptions, @@ -509,7 +508,7 @@ func TestAppSimulationAfterImport(t *testing.T) { t, os.Stdout, newSimApp.BaseApp, - sim.AppStateFn( + simulation2.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), diff --git a/simulation/sim/sim_utils.go b/simulation/utils.go similarity index 99% rename from simulation/sim/sim_utils.go rename to simulation/utils.go index e1ee19f307..faa727c65f 100644 --- a/simulation/sim/sim_utils.go +++ b/simulation/utils.go @@ -1,4 +1,4 @@ -package sim +package simulation import ( "encoding/json" From 6cc76e8d6ed40163dc01a4a202c340a1ecce034a Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 30 Oct 2024 12:30:50 -0400 Subject: [PATCH 56/59] remove directory sim --- .github/workflows/sim.yaml | 6 +- simulation/simulation.go | 322 +++++----------------------------- simulation/simulation_test.go | 80 ++++----- simulation/state.go | 297 +++++++++++++++++++++++++++++++ simulation/utils.go | 54 ------ 5 files changed, 382 insertions(+), 377 deletions(-) create mode 100644 simulation/state.go diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index 1d9b893125..11e6858a81 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -36,7 +36,7 @@ jobs: matrix-conditionals: needs: changed-files if: | - contains(github.event.pull_request.labels.*.name, 'simulation_tests') || needs.changed-files.outputs.modified_files + contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files runs-on: ubuntu-22.04 outputs: SIM_TEST_NOND: ${{ steps.matrix-conditionals.outputs.SIM_TEST_NOND }} @@ -62,7 +62,7 @@ jobs: needs: - matrix-conditionals if: | - contains(github.event.pull_request.labels.*.name, 'simulation_tests') || needs.changed-files.outputs.modified_files + contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files runs-on: ubuntu-22.04 strategy: fail-fast: false @@ -98,7 +98,7 @@ jobs: needs: - simulation-tests if: | - contains(github.event.pull_request.labels.*.name, 'simulation_tests') || needs.changed-files.outputs.modified_files + contains(github.event.pull_request.labels.*.name, 'SIM_TESTS') || needs.changed-files.outputs.modified_files runs-on: ubuntu-22.04 steps: - name: Aggregate Results diff --git a/simulation/simulation.go b/simulation/simulation.go index 540cd0aca7..1b1c29d876 100644 --- a/simulation/simulation.go +++ b/simulation/simulation.go @@ -1,297 +1,59 @@ package simulation import ( - "encoding/json" - "fmt" - "io" - "math/rand" - "os" - "time" - - "cosmossdk.io/math" - cmtjson "github.com/cometbft/cometbft/libs/json" - tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - 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" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - evmtypes "github.com/zeta-chain/ethermint/x/evm/types" + dbm "github.com/cometbft/cometbft-db" + "github.com/cometbft/cometbft/libs/log" + "github.com/cosmos/cosmos-sdk/baseapp" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/zeta-chain/ethermint/app" + evmante "github.com/zeta-chain/ethermint/app/ante" zetaapp "github.com/zeta-chain/node/app" + "github.com/zeta-chain/node/app/ante" ) -// 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.Codec, - 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 FlagGenesisTimeValue == 0 { - genesisTimestamp = simtypes.RandTimestamp(r) - } else { - genesisTimestamp = time.Unix(FlagGenesisTimeValue, 0) - } - - chainID = config.ChainID - switch { - case config.ParamsFile != "" && config.GenesisFile != "": - panic("cannot provide both a genesis file and a params file") - - case config.GenesisFile != "": - // override the default chain-id from simapp to set it later to the config - genesisDoc, accounts, err := AppStateFromGenesisFileFn(r, cdc, config.GenesisFile) - if err != nil { - panic(err) - } - - if FlagGenesisTimeValue == 0 { - // use genesis timestamp if no custom timestamp is provided (i.e no random timestamp) - genesisTimestamp = genesisDoc.GenesisTime - } - - appState = genesisDoc.AppState - chainID = genesisDoc.ChainID - simAccs = accounts - - case config.ParamsFile != "": - appParams := make(simtypes.AppParams) - bz, err := os.ReadFile(config.ParamsFile) - if err != nil { - panic(err) - } - - err = json.Unmarshal(bz, &appParams) - if err != nil { - panic(err) - } - appState, simAccs = AppStateRandomizedFn( - simManager, - r, - cdc, - accs, - genesisTimestamp, - appParams, - genesisState, - ) - - default: - appParams := make(simtypes.AppParams) - appState, simAccs = AppStateRandomizedFn( - simManager, - r, - cdc, - accs, - genesisTimestamp, - appParams, - genesisState, - ) - } - - rawState := make(map[string]json.RawMessage) - err := json.Unmarshal(appState, &rawState) - if err != nil { - panic(err) - } - - stakingStateBz, ok := rawState[stakingtypes.ModuleName] - if !ok { - panic("staking genesis state is missing") - } - - stakingState := new(stakingtypes.GenesisState) - err = cdc.UnmarshalJSON(stakingStateBz, stakingState) - if err != nil { - panic(err) - } - - // compute not bonded balance - notBondedTokens := math.ZeroInt() - for _, val := range stakingState.Validators { - if val.Status != stakingtypes.Unbonded { - continue - } - notBondedTokens = notBondedTokens.Add(val.GetTokens()) - } - notBondedCoins := sdk.NewCoin(stakingState.Params.BondDenom, notBondedTokens) - - // edit bank state to make it have the not bonded pool tokens - bankStateBz, ok := rawState[banktypes.ModuleName] - if !ok { - panic("bank genesis state is missing") - } - bankState := new(banktypes.GenesisState) - err = cdc.UnmarshalJSON(bankStateBz, bankState) - if err != nil { - panic(err) - } - - stakingAddr := authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName).String() - var found bool - for _, balance := range bankState.Balances { - if balance.Address == stakingAddr { - found = true - break - } - } - if !found { - bankState.Balances = append(bankState.Balances, banktypes.Balance{ - Address: stakingAddr, - Coins: sdk.NewCoins(notBondedCoins), - }) - } - - // Set the bond denom in the EVM genesis state - evmStateBz, ok := rawState[evmtypes.ModuleName] - if !ok { - panic("evm genesis state is missing") - } - - evmState := new(evmtypes.GenesisState) - cdc.MustUnmarshalJSON(evmStateBz, evmState) - - // we should replace the EvmDenom with BondDenom - evmState.Params.EvmDenom = stakingState.Params.BondDenom - - // change appState back - rawState[evmtypes.ModuleName] = cdc.MustMarshalJSON(evmState) - rawState[stakingtypes.ModuleName] = cdc.MustMarshalJSON(stakingState) - rawState[banktypes.ModuleName] = cdc.MustMarshalJSON(bankState) - - // replace appstate - appState, err = json.Marshal(rawState) - if err != nil { - panic(err) - } - return appState, simAccs, chainID, genesisTimestamp - } -} - -// AppStateRandomizedFn creates calls each module's GenesisState generator function -// and creates the simulation params -func AppStateRandomizedFn( - simManager *module.SimulationManager, r *rand.Rand, cdc codec.Codec, - accs []simtypes.Account, genesisTimestamp time.Time, appParams simtypes.AppParams, - genesisState map[string]json.RawMessage, -) (json.RawMessage, []simtypes.Account) { - numAccs := int64(len(accs)) - // generate a random amount of initial stake coins and a random initial - // number of bonded accounts - var ( - numInitiallyBonded int64 - initialStake math.Int - ) - - appParams.GetOrGenerate(cdc, - StakePerAccount, &initialStake, r, - func(r *rand.Rand) { initialStake = math.NewInt(r.Int63n(1e12)) }, - ) - appParams.GetOrGenerate(cdc, - InitiallyBondedValidators, &numInitiallyBonded, r, - func(r *rand.Rand) { numInitiallyBonded = int64(r.Intn(300)) }, - ) - - if numInitiallyBonded > numAccs { - numInitiallyBonded = numAccs - } - - // Set the default power reduction to be one less than the initial stake so that all randomised validators are part of the validator set - sdk.DefaultPowerReduction = initialStake.Sub(sdk.OneInt()) - - fmt.Printf( - `Selected randomly generated parameters for simulated genesis: -{ - stake_per_account: "%d", - initially_bonded_validators: "%d" -} -`, initialStake, numInitiallyBonded, +func NewSimApp( + logger log.Logger, + db dbm.DB, + appOptions servertypes.AppOptions, + baseAppOptions ...func(*baseapp.BaseApp), +) (*zetaapp.App, error) { + encCdc := zetaapp.MakeEncodingConfig() + + // Set load latest version to false as we manually set it later. + zetaApp := zetaapp.New( + logger, + db, + nil, + false, + map[int64]bool{}, + app.DefaultNodeHome, + 5, + encCdc, + appOptions, + baseAppOptions..., ) - simState := &module.SimulationState{ - AppParams: appParams, - Cdc: cdc, - Rand: r, - GenState: genesisState, - Accounts: accs, - InitialStake: initialStake, - NumBonded: numInitiallyBonded, - GenTimestamp: genesisTimestamp, + // use zeta antehandler + options := ante.HandlerOptions{ + AccountKeeper: zetaApp.AccountKeeper, + BankKeeper: zetaApp.BankKeeper, + EvmKeeper: zetaApp.EvmKeeper, + FeeMarketKeeper: zetaApp.FeeMarketKeeper, + SignModeHandler: encCdc.TxConfig.SignModeHandler(), + SigGasConsumer: evmante.DefaultSigVerificationGasConsumer, + MaxTxGasWanted: 0, + ObserverKeeper: zetaApp.ObserverKeeper, } - simManager.GenerateGenesisStates(simState) - - appState, err := json.Marshal(genesisState) + anteHandler, err := ante.NewAnteHandler(options) if err != nil { panic(err) } - return appState, accs -} - -// AppStateFromGenesisFileFn util function to generate the genesis AppState -// from a genesis.json file. -func AppStateFromGenesisFileFn( - r io.Reader, - cdc codec.JSONCodec, - genesisFile string, -) (tmtypes.GenesisDoc, []simtypes.Account, error) { - bytes, err := os.ReadFile(genesisFile) // #nosec G304 -- genesisFile value is controlled - if err != nil { - panic(err) + zetaApp.SetAnteHandler(anteHandler) + if err := zetaApp.LoadLatestVersion(); err != nil { + return nil, err } - - var genesis tmtypes.GenesisDoc - // NOTE: Comet uses a custom JSON decoder for GenesisDoc - err = cmtjson.Unmarshal(bytes, &genesis) - if err != nil { - panic(err) - } - - var appState zetaapp.GenesisState - err = json.Unmarshal(genesis.AppState, &appState) - if err != nil { - panic(err) - } - - var authGenesis authtypes.GenesisState - if appState[authtypes.ModuleName] != nil { - cdc.MustUnmarshalJSON(appState[authtypes.ModuleName], &authGenesis) - } - - newAccs := make([]simtypes.Account, len(authGenesis.Accounts)) - for i, acc := range authGenesis.Accounts { - // Pick a random private key, since we don't know the actual key - // This should be fine as it's only used for mock Tendermint validators - // and these keys are never actually used to sign by mock Tendermint. - privkeySeed := make([]byte, 15) - if _, err := r.Read(privkeySeed); err != nil { - panic(err) - } - - privKey := secp256k1.GenPrivKeyFromSecret(privkeySeed) - - a, ok := acc.GetCachedValue().(authtypes.AccountI) - if !ok { - return genesis, nil, fmt.Errorf("expected account") - } - - // create simulator accounts - simAcc := simtypes.Account{PrivKey: privKey, PubKey: privKey.PubKey(), Address: a.GetAddress()} - newAccs[i] = simAcc - } - - return genesis, newAccs, nil + return zetaApp, nil } diff --git a/simulation/simulation_test.go b/simulation/simulation_test.go index ee6a036338..0c85a718f6 100644 --- a/simulation/simulation_test.go +++ b/simulation/simulation_test.go @@ -24,7 +24,7 @@ import ( "github.com/stretchr/testify/require" evmtypes "github.com/zeta-chain/ethermint/x/evm/types" "github.com/zeta-chain/node/app" - simulation2 "github.com/zeta-chain/node/simulation" + zetasimulation "github.com/zeta-chain/node/simulation" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client/flags" @@ -38,7 +38,7 @@ import ( // AppChainID hardcoded chainID for simulation func init() { - simulation2.GetSimulatorFlags() + zetasimulation.GetSimulatorFlags() } type StoreKeysPrefixes struct { @@ -67,11 +67,11 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { // The following test certifies that , for the same set of operations ( irrespective of what the operations are ) , // we would reach the same final state if the initial state is the same func TestAppStateDeterminism(t *testing.T) { - if !simulation2.FlagEnabledValue { + if !zetasimulation.FlagEnabledValue { t.Skip("skipping application simulation") } - config := simulation2.NewConfigFromFlags() + config := zetasimulation.NewConfigFromFlags() config.InitialBlockHeight = 1 config.ExportParamsPath = "" @@ -92,7 +92,7 @@ func TestAppStateDeterminism(t *testing.T) { appHashList := make([]json.RawMessage, numTimesToRunPerSeed) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = simulation2.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = zetasimulation.FlagPeriodValue t.Log("Running tests for numSeeds: ", numSeeds, " numTimesToRunPerSeed: ", numTimesToRunPerSeed) @@ -106,13 +106,13 @@ func TestAppStateDeterminism(t *testing.T) { config, SimDBBackend, SimDBName, - simulation2.FlagVerboseValue, - simulation2.FlagEnabledValue, + zetasimulation.FlagVerboseValue, + zetasimulation.FlagEnabledValue, ) require.NoError(t, err) appOptions[flags.FlagHome] = dir - simApp, err := simulation2.NewSimApp( + simApp, err := zetasimulation.NewSimApp( logger, db, appOptions, @@ -132,7 +132,7 @@ func TestAppStateDeterminism(t *testing.T) { t, os.Stdout, simApp.BaseApp, - simulation2.AppStateFn( + zetasimulation.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -145,7 +145,7 @@ func TestAppStateDeterminism(t *testing.T) { ) require.NoError(t, err) - simulation2.PrintStats(db) + zetasimulation.PrintStats(db) appHash := simApp.LastCommitID().Hash appHashList[j] = appHash @@ -177,7 +177,7 @@ func TestAppStateDeterminism(t *testing.T) { // At the end of the run it tries to export the genesis state to make sure the export works. func TestFullAppSimulation(t *testing.T) { - config := simulation2.NewConfigFromFlags() + config := zetasimulation.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas @@ -187,8 +187,8 @@ func TestFullAppSimulation(t *testing.T) { config, SimDBBackend, SimDBName, - simulation2.FlagVerboseValue, - simulation2.FlagEnabledValue, + zetasimulation.FlagVerboseValue, + zetasimulation.FlagEnabledValue, ) if skip { t.Skip("skipping application simulation") @@ -204,10 +204,10 @@ func TestFullAppSimulation(t *testing.T) { } }) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = simulation2.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = zetasimulation.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := simulation2.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := zetasimulation.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) blockedAddresses := simApp.ModuleAccountAddrs() @@ -215,7 +215,7 @@ func TestFullAppSimulation(t *testing.T) { t, os.Stdout, simApp.BaseApp, - simulation2.AppStateFn( + zetasimulation.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -236,11 +236,11 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, err) } - simulation2.PrintStats(db) + zetasimulation.PrintStats(db) } func TestAppImportExport(t *testing.T) { - config := simulation2.NewConfigFromFlags() + config := zetasimulation.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas @@ -250,8 +250,8 @@ func TestAppImportExport(t *testing.T) { config, SimDBBackend, SimDBName, - simulation2.FlagVerboseValue, - simulation2.FlagEnabledValue, + zetasimulation.FlagVerboseValue, + zetasimulation.FlagEnabledValue, ) if skip { t.Skip("skipping application simulation") @@ -268,9 +268,9 @@ func TestAppImportExport(t *testing.T) { }) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = simulation2.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = zetasimulation.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := simulation2.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := zetasimulation.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) // Run randomized simulation @@ -279,7 +279,7 @@ func TestAppImportExport(t *testing.T) { t, os.Stdout, simApp.BaseApp, - simulation2.AppStateFn( + zetasimulation.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -292,10 +292,10 @@ func TestAppImportExport(t *testing.T) { ) require.NoError(t, simErr) - err = simulation2.CheckExportSimulation(simApp, config, simParams) + err = zetasimulation.CheckExportSimulation(simApp, config, simParams) require.NoError(t, err) - simulation2.PrintStats(db) + zetasimulation.PrintStats(db) t.Log("exporting genesis") // export state and simParams @@ -307,8 +307,8 @@ func TestAppImportExport(t *testing.T) { config, SimDBBackend+"_new", SimDBName+"_new", - simulation2.FlagVerboseValue, - simulation2.FlagEnabledValue, + zetasimulation.FlagVerboseValue, + zetasimulation.FlagEnabledValue, ) require.NoError(t, err, "simulation setup failed") @@ -322,7 +322,7 @@ func TestAppImportExport(t *testing.T) { } }) - newSimApp, err := simulation2.NewSimApp( + newSimApp, err := zetasimulation.NewSimApp( logger, newDB, appOptions, @@ -401,7 +401,7 @@ func TestAppImportExport(t *testing.T) { } func TestAppSimulationAfterImport(t *testing.T) { - config := simulation2.NewConfigFromFlags() + config := zetasimulation.NewConfigFromFlags() config.ChainID = SimAppChainID config.BlockMaxGas = SimBlockMaxGas @@ -411,8 +411,8 @@ func TestAppSimulationAfterImport(t *testing.T) { config, SimDBBackend, SimDBName, - simulation2.FlagVerboseValue, - simulation2.FlagEnabledValue, + zetasimulation.FlagVerboseValue, + zetasimulation.FlagEnabledValue, ) if skip { t.Skip("skipping application simulation") @@ -429,9 +429,9 @@ func TestAppSimulationAfterImport(t *testing.T) { }) appOptions := make(cosmossimutils.AppOptionsMap, 0) - appOptions[server.FlagInvCheckPeriod] = simulation2.FlagPeriodValue + appOptions[server.FlagInvCheckPeriod] = zetasimulation.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := simulation2.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := zetasimulation.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) require.NoError(t, err) // Run randomized simulation @@ -440,7 +440,7 @@ func TestAppSimulationAfterImport(t *testing.T) { t, os.Stdout, simApp.BaseApp, - simulation2.AppStateFn( + zetasimulation.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), @@ -453,10 +453,10 @@ func TestAppSimulationAfterImport(t *testing.T) { ) require.NoError(t, simErr) - err = simulation2.CheckExportSimulation(simApp, config, simParams) + err = zetasimulation.CheckExportSimulation(simApp, config, simParams) require.NoError(t, err) - simulation2.PrintStats(db) + zetasimulation.PrintStats(db) if stopEarly { t.Log("can't export or import a zero-validator genesis, exiting test") @@ -475,8 +475,8 @@ func TestAppSimulationAfterImport(t *testing.T) { config, SimDBBackend+"_new", SimDBName+"_new", - simulation2.FlagVerboseValue, - simulation2.FlagEnabledValue, + zetasimulation.FlagVerboseValue, + zetasimulation.FlagEnabledValue, ) require.NoError(t, err, "simulation setup failed") @@ -490,7 +490,7 @@ func TestAppSimulationAfterImport(t *testing.T) { } }) - newSimApp, err := simulation2.NewSimApp( + newSimApp, err := zetasimulation.NewSimApp( logger, newDB, appOptions, @@ -508,7 +508,7 @@ func TestAppSimulationAfterImport(t *testing.T) { t, os.Stdout, newSimApp.BaseApp, - simulation2.AppStateFn( + zetasimulation.AppStateFn( simApp.AppCodec(), simApp.SimulationManager(), simApp.BasicManager().DefaultGenesis(simApp.AppCodec()), diff --git a/simulation/state.go b/simulation/state.go new file mode 100644 index 0000000000..540cd0aca7 --- /dev/null +++ b/simulation/state.go @@ -0,0 +1,297 @@ +package simulation + +import ( + "encoding/json" + "fmt" + "io" + "math/rand" + "os" + "time" + + "cosmossdk.io/math" + cmtjson "github.com/cometbft/cometbft/libs/json" + tmtypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + 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" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + evmtypes "github.com/zeta-chain/ethermint/x/evm/types" + + zetaapp "github.com/zeta-chain/node/app" +) + +// 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.Codec, + 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 FlagGenesisTimeValue == 0 { + genesisTimestamp = simtypes.RandTimestamp(r) + } else { + genesisTimestamp = time.Unix(FlagGenesisTimeValue, 0) + } + + chainID = config.ChainID + switch { + case config.ParamsFile != "" && config.GenesisFile != "": + panic("cannot provide both a genesis file and a params file") + + case config.GenesisFile != "": + // override the default chain-id from simapp to set it later to the config + genesisDoc, accounts, err := AppStateFromGenesisFileFn(r, cdc, config.GenesisFile) + if err != nil { + panic(err) + } + + if FlagGenesisTimeValue == 0 { + // use genesis timestamp if no custom timestamp is provided (i.e no random timestamp) + genesisTimestamp = genesisDoc.GenesisTime + } + + appState = genesisDoc.AppState + chainID = genesisDoc.ChainID + simAccs = accounts + + case config.ParamsFile != "": + appParams := make(simtypes.AppParams) + bz, err := os.ReadFile(config.ParamsFile) + if err != nil { + panic(err) + } + + err = json.Unmarshal(bz, &appParams) + if err != nil { + panic(err) + } + appState, simAccs = AppStateRandomizedFn( + simManager, + r, + cdc, + accs, + genesisTimestamp, + appParams, + genesisState, + ) + + default: + appParams := make(simtypes.AppParams) + appState, simAccs = AppStateRandomizedFn( + simManager, + r, + cdc, + accs, + genesisTimestamp, + appParams, + genesisState, + ) + } + + rawState := make(map[string]json.RawMessage) + err := json.Unmarshal(appState, &rawState) + if err != nil { + panic(err) + } + + stakingStateBz, ok := rawState[stakingtypes.ModuleName] + if !ok { + panic("staking genesis state is missing") + } + + stakingState := new(stakingtypes.GenesisState) + err = cdc.UnmarshalJSON(stakingStateBz, stakingState) + if err != nil { + panic(err) + } + + // compute not bonded balance + notBondedTokens := math.ZeroInt() + for _, val := range stakingState.Validators { + if val.Status != stakingtypes.Unbonded { + continue + } + notBondedTokens = notBondedTokens.Add(val.GetTokens()) + } + notBondedCoins := sdk.NewCoin(stakingState.Params.BondDenom, notBondedTokens) + + // edit bank state to make it have the not bonded pool tokens + bankStateBz, ok := rawState[banktypes.ModuleName] + if !ok { + panic("bank genesis state is missing") + } + bankState := new(banktypes.GenesisState) + err = cdc.UnmarshalJSON(bankStateBz, bankState) + if err != nil { + panic(err) + } + + stakingAddr := authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName).String() + var found bool + for _, balance := range bankState.Balances { + if balance.Address == stakingAddr { + found = true + break + } + } + if !found { + bankState.Balances = append(bankState.Balances, banktypes.Balance{ + Address: stakingAddr, + Coins: sdk.NewCoins(notBondedCoins), + }) + } + + // Set the bond denom in the EVM genesis state + evmStateBz, ok := rawState[evmtypes.ModuleName] + if !ok { + panic("evm genesis state is missing") + } + + evmState := new(evmtypes.GenesisState) + cdc.MustUnmarshalJSON(evmStateBz, evmState) + + // we should replace the EvmDenom with BondDenom + evmState.Params.EvmDenom = stakingState.Params.BondDenom + + // change appState back + rawState[evmtypes.ModuleName] = cdc.MustMarshalJSON(evmState) + rawState[stakingtypes.ModuleName] = cdc.MustMarshalJSON(stakingState) + rawState[banktypes.ModuleName] = cdc.MustMarshalJSON(bankState) + + // replace appstate + appState, err = json.Marshal(rawState) + if err != nil { + panic(err) + } + return appState, simAccs, chainID, genesisTimestamp + } +} + +// AppStateRandomizedFn creates calls each module's GenesisState generator function +// and creates the simulation params +func AppStateRandomizedFn( + simManager *module.SimulationManager, r *rand.Rand, cdc codec.Codec, + accs []simtypes.Account, genesisTimestamp time.Time, appParams simtypes.AppParams, + genesisState map[string]json.RawMessage, +) (json.RawMessage, []simtypes.Account) { + numAccs := int64(len(accs)) + // generate a random amount of initial stake coins and a random initial + // number of bonded accounts + var ( + numInitiallyBonded int64 + initialStake math.Int + ) + + appParams.GetOrGenerate(cdc, + StakePerAccount, &initialStake, r, + func(r *rand.Rand) { initialStake = math.NewInt(r.Int63n(1e12)) }, + ) + appParams.GetOrGenerate(cdc, + InitiallyBondedValidators, &numInitiallyBonded, r, + func(r *rand.Rand) { numInitiallyBonded = int64(r.Intn(300)) }, + ) + + if numInitiallyBonded > numAccs { + numInitiallyBonded = numAccs + } + + // Set the default power reduction to be one less than the initial stake so that all randomised validators are part of the validator set + sdk.DefaultPowerReduction = initialStake.Sub(sdk.OneInt()) + + fmt.Printf( + `Selected randomly generated parameters for simulated genesis: +{ + stake_per_account: "%d", + initially_bonded_validators: "%d" +} +`, initialStake, numInitiallyBonded, + ) + + simState := &module.SimulationState{ + AppParams: appParams, + Cdc: cdc, + Rand: r, + GenState: genesisState, + Accounts: accs, + InitialStake: initialStake, + NumBonded: numInitiallyBonded, + GenTimestamp: genesisTimestamp, + } + + simManager.GenerateGenesisStates(simState) + + appState, err := json.Marshal(genesisState) + if err != nil { + panic(err) + } + + return appState, accs +} + +// AppStateFromGenesisFileFn util function to generate the genesis AppState +// from a genesis.json file. +func AppStateFromGenesisFileFn( + r io.Reader, + cdc codec.JSONCodec, + genesisFile string, +) (tmtypes.GenesisDoc, []simtypes.Account, error) { + bytes, err := os.ReadFile(genesisFile) // #nosec G304 -- genesisFile value is controlled + if err != nil { + panic(err) + } + + var genesis tmtypes.GenesisDoc + // NOTE: Comet uses a custom JSON decoder for GenesisDoc + err = cmtjson.Unmarshal(bytes, &genesis) + if err != nil { + panic(err) + } + + var appState zetaapp.GenesisState + err = json.Unmarshal(genesis.AppState, &appState) + if err != nil { + panic(err) + } + + var authGenesis authtypes.GenesisState + if appState[authtypes.ModuleName] != nil { + cdc.MustUnmarshalJSON(appState[authtypes.ModuleName], &authGenesis) + } + + newAccs := make([]simtypes.Account, len(authGenesis.Accounts)) + for i, acc := range authGenesis.Accounts { + // Pick a random private key, since we don't know the actual key + // This should be fine as it's only used for mock Tendermint validators + // and these keys are never actually used to sign by mock Tendermint. + privkeySeed := make([]byte, 15) + if _, err := r.Read(privkeySeed); err != nil { + panic(err) + } + + privKey := secp256k1.GenPrivKeyFromSecret(privkeySeed) + + a, ok := acc.GetCachedValue().(authtypes.AccountI) + if !ok { + return genesis, nil, fmt.Errorf("expected account") + } + + // create simulator accounts + simAcc := simtypes.Account{PrivKey: privKey, PubKey: privKey.PubKey(), Address: a.GetAddress()} + newAccs[i] = simAcc + } + + return genesis, newAccs, nil +} diff --git a/simulation/utils.go b/simulation/utils.go index faa727c65f..257f7bcaa1 100644 --- a/simulation/utils.go +++ b/simulation/utils.go @@ -6,64 +6,10 @@ import ( "os" dbm "github.com/cometbft/cometbft-db" - "github.com/cometbft/cometbft/libs/log" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/runtime" - servertypes "github.com/cosmos/cosmos-sdk/server/types" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/zeta-chain/ethermint/app" - evmante "github.com/zeta-chain/ethermint/app/ante" - - zetaapp "github.com/zeta-chain/node/app" - "github.com/zeta-chain/node/app/ante" ) -func NewSimApp( - logger log.Logger, - db dbm.DB, - appOptions servertypes.AppOptions, - baseAppOptions ...func(*baseapp.BaseApp), -) (*zetaapp.App, error) { - encCdc := zetaapp.MakeEncodingConfig() - - // Set load latest version to false as we manually set it later. - zetaApp := zetaapp.New( - logger, - db, - nil, - false, - map[int64]bool{}, - app.DefaultNodeHome, - 5, - encCdc, - appOptions, - baseAppOptions..., - ) - - // use zeta antehandler - options := ante.HandlerOptions{ - AccountKeeper: zetaApp.AccountKeeper, - BankKeeper: zetaApp.BankKeeper, - EvmKeeper: zetaApp.EvmKeeper, - FeeMarketKeeper: zetaApp.FeeMarketKeeper, - SignModeHandler: encCdc.TxConfig.SignModeHandler(), - SigGasConsumer: evmante.DefaultSigVerificationGasConsumer, - MaxTxGasWanted: 0, - ObserverKeeper: zetaApp.ObserverKeeper, - } - - anteHandler, err := ante.NewAnteHandler(options) - if err != nil { - panic(err) - } - - zetaApp.SetAnteHandler(anteHandler) - if err := zetaApp.LoadLatestVersion(); err != nil { - return nil, err - } - return zetaApp, nil -} - // PrintStats prints the corresponding statistics from the app DB. func PrintStats(db dbm.DB) { fmt.Println("\nDB Stats") From d8b713a359e72a66135b20077869822d3ac0367f Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 30 Oct 2024 13:26:43 -0400 Subject: [PATCH 57/59] format directory --- simulation/simulation_test.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/simulation/simulation_test.go b/simulation/simulation_test.go index 0c85a718f6..3f39c77fa1 100644 --- a/simulation/simulation_test.go +++ b/simulation/simulation_test.go @@ -207,7 +207,13 @@ func TestFullAppSimulation(t *testing.T) { appOptions[server.FlagInvCheckPeriod] = zetasimulation.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := zetasimulation.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := zetasimulation.NewSimApp( + logger, + db, + appOptions, + interBlockCacheOpt(), + baseapp.SetChainID(SimAppChainID), + ) require.NoError(t, err) blockedAddresses := simApp.ModuleAccountAddrs() @@ -270,7 +276,13 @@ func TestAppImportExport(t *testing.T) { appOptions := make(cosmossimutils.AppOptionsMap, 0) appOptions[server.FlagInvCheckPeriod] = zetasimulation.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := zetasimulation.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := zetasimulation.NewSimApp( + logger, + db, + appOptions, + interBlockCacheOpt(), + baseapp.SetChainID(SimAppChainID), + ) require.NoError(t, err) // Run randomized simulation @@ -431,7 +443,13 @@ func TestAppSimulationAfterImport(t *testing.T) { appOptions := make(cosmossimutils.AppOptionsMap, 0) appOptions[server.FlagInvCheckPeriod] = zetasimulation.FlagPeriodValue appOptions[flags.FlagHome] = dir - simApp, err := zetasimulation.NewSimApp(logger, db, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + simApp, err := zetasimulation.NewSimApp( + logger, + db, + appOptions, + interBlockCacheOpt(), + baseapp.SetChainID(SimAppChainID), + ) require.NoError(t, err) // Run randomized simulation From 60a0aa415bcd93082cf76bd9f2a406dfd678311c Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 31 Oct 2024 11:00:20 -0400 Subject: [PATCH 58/59] remove utils file --- simulation/simulation.go | 40 +++++++++++++++++++++++++++++++++++ simulation/utils.go | 45 ---------------------------------------- 2 files changed, 40 insertions(+), 45 deletions(-) delete mode 100644 simulation/utils.go diff --git a/simulation/simulation.go b/simulation/simulation.go index 1b1c29d876..faa727c65f 100644 --- a/simulation/simulation.go +++ b/simulation/simulation.go @@ -1,10 +1,16 @@ package simulation import ( + "encoding/json" + "fmt" + "os" + dbm "github.com/cometbft/cometbft-db" "github.com/cometbft/cometbft/libs/log" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/runtime" servertypes "github.com/cosmos/cosmos-sdk/server/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/zeta-chain/ethermint/app" evmante "github.com/zeta-chain/ethermint/app/ante" @@ -57,3 +63,37 @@ func NewSimApp( } return zetaApp, nil } + +// PrintStats prints the corresponding statistics from the app DB. +func PrintStats(db dbm.DB) { + fmt.Println("\nDB Stats") + fmt.Println(db.Stats()["leveldb.stats"]) + fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) +} + +// CheckExportSimulation exports the app state and simulation parameters to JSON +// if the export paths are defined. +func CheckExportSimulation(app runtime.AppI, config simtypes.Config, params simtypes.Params) error { + if config.ExportStatePath != "" { + exported, err := app.ExportAppStateAndValidators(false, nil, nil) + if err != nil { + return fmt.Errorf("failed to export app state: %w", err) + } + + if err := os.WriteFile(config.ExportStatePath, exported.AppState, 0o600); err != nil { + return err + } + } + + if config.ExportParamsPath != "" { + paramsBz, err := json.MarshalIndent(params, "", " ") + if err != nil { + return fmt.Errorf("failed to write app state to %s: %w", config.ExportStatePath, err) + } + + if err := os.WriteFile(config.ExportParamsPath, paramsBz, 0o600); err != nil { + return err + } + } + return nil +} diff --git a/simulation/utils.go b/simulation/utils.go deleted file mode 100644 index 257f7bcaa1..0000000000 --- a/simulation/utils.go +++ /dev/null @@ -1,45 +0,0 @@ -package simulation - -import ( - "encoding/json" - "fmt" - "os" - - dbm "github.com/cometbft/cometbft-db" - "github.com/cosmos/cosmos-sdk/runtime" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" -) - -// PrintStats prints the corresponding statistics from the app DB. -func PrintStats(db dbm.DB) { - fmt.Println("\nDB Stats") - fmt.Println(db.Stats()["leveldb.stats"]) - fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) -} - -// CheckExportSimulation exports the app state and simulation parameters to JSON -// if the export paths are defined. -func CheckExportSimulation(app runtime.AppI, config simtypes.Config, params simtypes.Params) error { - if config.ExportStatePath != "" { - exported, err := app.ExportAppStateAndValidators(false, nil, nil) - if err != nil { - return fmt.Errorf("failed to export app state: %w", err) - } - - if err := os.WriteFile(config.ExportStatePath, exported.AppState, 0o600); err != nil { - return err - } - } - - if config.ExportParamsPath != "" { - paramsBz, err := json.MarshalIndent(params, "", " ") - if err != nil { - return fmt.Errorf("failed to write app state to %s: %w", config.ExportStatePath, err) - } - - if err := os.WriteFile(config.ExportParamsPath, paramsBz, 0o600); err != nil { - return err - } - } - return nil -} From b9abe91f7191ba73c2142a209d3d041d70a66725 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 31 Oct 2024 22:10:43 -0400 Subject: [PATCH 59/59] add to codecov --- codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecov.yml b/codecov.yml index 7778c1672d..da90e44bd9 100644 --- a/codecov.yml +++ b/codecov.yml @@ -81,4 +81,4 @@ ignore: - "precompiles/**/*.json" - "precompiles/**/*.sol" - "precompiles/**/*.gen.go" - - "simulation/**/*" + - "simulation/*.go"