Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: extract AppStateFn out of simapp (backport #14977) #14978

Merged
merged 2 commits into from
Feb 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Improvements

* (simapp) [#14977](https://github.com/cosmos/cosmos-sdk/pull/14977) Move simulation helpers functions (`AppStateFn` and `AppStateRandomizedFn`) to `testutil/sims`. These takes an extra genesisState argument which is the default state of the app.
* (cli) [#14953](https://github.com/cosmos/cosmos-sdk/pull/14953) Enable profiling block replay during abci handshake with `--cpu-profile`.
* (store) [#14410](https://github.com/cosmos/cosmos-sdk/pull/14410) `rootmulti.Store.loadVersion` has validation to check if all the module stores' height is correct, it will error if any module store has incorrect height.
* (store) [#14189](https://github.com/cosmos/cosmos-sdk/pull/14189) Add config `iavl-lazy-loading` to enable lazy loading of iavl store, to improve start up time of archive nodes, add method `SetLazyLoading` to `CommitMultiStore` interface.
Expand Down
7 changes: 0 additions & 7 deletions simapp/params/params.go

This file was deleted.

4 changes: 2 additions & 2 deletions simapp/sim_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func BenchmarkFullAppSimulation(b *testing.B) {
b,
os.Stdout,
app.BaseApp,
AppStateFn(app.AppCodec(), app.SimulationManager()),
simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()),
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simtestutil.SimulationOperations(app, app.AppCodec(), config),
BlockedAddresses(),
Expand Down Expand Up @@ -104,7 +104,7 @@ func BenchmarkInvariants(b *testing.B) {
b,
os.Stdout,
app.BaseApp,
AppStateFn(app.AppCodec(), app.SimulationManager()),
simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()),
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simtestutil.SimulationOperations(app, app.AppCodec(), config),
BlockedAddresses(),
Expand Down
10 changes: 5 additions & 5 deletions simapp/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func TestFullAppSimulation(t *testing.T) {
t,
os.Stdout,
app.BaseApp,
AppStateFn(app.AppCodec(), app.SimulationManager()),
simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()),
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simtestutil.SimulationOperations(app, app.AppCodec(), config),
BlockedAddresses(),
Expand Down Expand Up @@ -137,7 +137,7 @@ func TestAppImportExport(t *testing.T) {
t,
os.Stdout,
app.BaseApp,
AppStateFn(app.AppCodec(), app.SimulationManager()),
simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()),
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simtestutil.SimulationOperations(app, app.AppCodec(), config),
BlockedAddresses(),
Expand Down Expand Up @@ -253,7 +253,7 @@ func TestAppSimulationAfterImport(t *testing.T) {
t,
os.Stdout,
app.BaseApp,
AppStateFn(app.AppCodec(), app.SimulationManager()),
simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()),
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simtestutil.SimulationOperations(app, app.AppCodec(), config),
BlockedAddresses(),
Expand Down Expand Up @@ -301,7 +301,7 @@ func TestAppSimulationAfterImport(t *testing.T) {
t,
os.Stdout,
newApp.BaseApp,
AppStateFn(app.AppCodec(), app.SimulationManager()),
simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()),
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simtestutil.SimulationOperations(newApp, newApp.AppCodec(), config),
BlockedAddresses(),
Expand Down Expand Up @@ -356,7 +356,7 @@ func TestAppStateDeterminism(t *testing.T) {
t,
os.Stdout,
app.BaseApp,
AppStateFn(app.AppCodec(), app.SimulationManager()),
simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()),
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simtestutil.SimulationOperations(app, app.AppCodec(), config),
BlockedAddresses(),
Expand Down
64 changes: 38 additions & 26 deletions simapp/state.go → testutil/sims/state_helpers.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package simapp
package sims

import (
"encoding/json"
Expand All @@ -8,11 +8,10 @@ import (
"os"
"time"

"cosmossdk.io/math"
tmjson "github.com/tendermint/tendermint/libs/json"
tmtypes "github.com/tendermint/tendermint/types"

"cosmossdk.io/math"
simappparams "cosmossdk.io/simapp/params"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -24,11 +23,21 @@ import (
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

// Simulation parameter constants
const (
StakePerAccount = "stake_per_account"
InitiallyBondedValidators = "initially_bonded_validators"
)

// AppStateFn returns the initial application state using a genesis or the simulation parameters.
// It panics if the user provides files for both of them.
// If a file is not given for the genesis or the sim params, it creates a randomized one.
func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simtypes.AppStateFn {
return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config,
// genesisState is the default genesis state of the whole app.
func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager, genesisState map[string]json.RawMessage) simtypes.AppStateFn {
return func(
r *rand.Rand,
accs []simtypes.Account,
config simtypes.Config,
) (appState json.RawMessage, simAccs []simtypes.Account, chainID string, genesisTimestamp time.Time) {
if simcli.FlagGenesisTimeValue == 0 {
genesisTimestamp = simtypes.RandTimestamp(r)
Expand All @@ -43,7 +52,10 @@ func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simty

case config.GenesisFile != "":
// override the default chain-id from simapp to set it later to the config
genesisDoc, accounts := AppStateFromGenesisFileFn(r, cdc, config.GenesisFile)
genesisDoc, accounts, err := AppStateFromGenesisFileFn(r, cdc, config.GenesisFile)
if err != nil {
panic(err)
}

if simcli.FlagGenesisTimeValue == 0 {
// use genesis timestamp if no custom timestamp is provided (i.e no random timestamp)
Expand All @@ -65,11 +77,11 @@ func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simty
if err != nil {
panic(err)
}
appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams)
appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams, genesisState)

default:
appParams := make(simtypes.AppParams)
appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams)
appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams, genesisState)
}

rawState := make(map[string]json.RawMessage)
Expand All @@ -84,8 +96,7 @@ func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simty
}

stakingState := new(stakingtypes.GenesisState)
err = cdc.UnmarshalJSON(stakingStateBz, stakingState)
if err != nil {
if err = cdc.UnmarshalJSON(stakingStateBz, stakingState); err != nil {
panic(err)
}
// compute not bonded balance
Expand All @@ -104,8 +115,7 @@ func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simty
panic("bank genesis state is missing")
}
bankState := new(banktypes.GenesisState)
err = cdc.UnmarshalJSON(bankStateBz, bankState)
if err != nil {
if err = cdc.UnmarshalJSON(bankStateBz, bankState); err != nil {
panic(err)
}

Expand Down Expand Up @@ -140,24 +150,27 @@ func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simty
// AppStateRandomizedFn creates calls each module's GenesisState generator function
// and creates the simulation params
func AppStateRandomizedFn(
simManager *module.SimulationManager, r *rand.Rand, cdc codec.JSONCodec,
accs []simtypes.Account, genesisTimestamp time.Time, appParams simtypes.AppParams,
simManager *module.SimulationManager,
r *rand.Rand,
cdc codec.JSONCodec,
accs []simtypes.Account,
genesisTimestamp time.Time,
appParams simtypes.AppParams,
genesisState map[string]json.RawMessage,
) (json.RawMessage, []simtypes.Account) {
numAccs := int64(len(accs))
genesisState := ModuleBasics.DefaultGenesis(cdc)

// generate a random amount of initial stake coins and a random initial
// number of bonded accounts
var (
numInitiallyBonded int64
initialStake math.Int
)
appParams.GetOrGenerate(
cdc, simappparams.StakePerAccount, &initialStake, r,
cdc, StakePerAccount, &initialStake, r,
func(r *rand.Rand) { initialStake = math.NewInt(r.Int63n(1e12)) },
)
appParams.GetOrGenerate(
cdc, simappparams.InitiallyBondedValidators, &numInitiallyBonded, r,
cdc, InitiallyBondedValidators, &numInitiallyBonded, r,
func(r *rand.Rand) { numInitiallyBonded = int64(r.Intn(300)) },
)

Expand Down Expand Up @@ -197,7 +210,7 @@ func AppStateRandomizedFn(

// AppStateFromGenesisFileFn util function to generate the genesis AppState
// from a genesis.json file.
func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile string) (tmtypes.GenesisDoc, []simtypes.Account) {
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)
Expand All @@ -207,13 +220,12 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile str
// NOTE: Tendermint uses a custom JSON decoder for GenesisDoc
err = tmjson.Unmarshal(bytes, &genesis)
if err != nil {
panic(err)
return genesis, nil, err
}

var appState GenesisState
err = json.Unmarshal(genesis.AppState, &appState)
if err != nil {
panic(err)
var appState map[string]json.RawMessage
if err = json.Unmarshal(genesis.AppState, &appState); err != nil {
return genesis, nil, err
}

var authGenesis authtypes.GenesisState
Expand All @@ -235,13 +247,13 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile str

a, ok := acc.GetCachedValue().(authtypes.AccountI)
if !ok {
panic("expected account")
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
return genesis, newAccs, nil
}