Prerequisite Readings
Synopsis
This document guides developers on integrating their custom modules with the Cosmos SDKSimulations.
Simulations are useful for testing edge cases in module implementations.
- Simulation Package
- Simulation App Module
- SimsX
- Store decoders
- Randomized genesis
- Random weighted operations
- App Simulator manager
- Running Simulations
Simulation Package
The Cosmos SDK suggests organizing your simulation related code in ax/<module>/simulation package.
Simulation App Module
To integrate with the Cosmos SDKSimulationManager, app modules must implement the AppModuleSimulation interface.
types/module/simulation.go.
See an example implementation of these methods from x/distribution here.
SimsX
Cosmos SDK v0.53.0 introduced a new package,simsx, providing improved DevX for writing simulation code.
It exposes the following extension interfaces that modules may implement to integrate with the new simsx runner.
testutil/simsx/runner.go.
SimMsgFactoryFn is the default factory for most cases. It does not create future operations but ensures successful message delivery:
testutil/simsx/msg_factory.go.
These methods allow constructing randomized messages and/or proposal messages.
Example Implementations
Store decoders
Registering the store decoders is required for theAppImportExport simulation. This allows
for the key-value pairs from the stores to be decoded to their corresponding types.
In particular, it matches the key to a concrete type and then unmarshalls the value from the KVPair to the type provided.
Modules using collections can use the NewStoreDecoderFuncFromCollectionsSchema function that builds the decoder for you:
types/simulation/collections.go and the bank module example at x/bank/module.go.
Modules not using collections must manually build the store decoder.
See the implementation here from the distribution module for an example.
Randomized genesis
The simulator tests different scenarios and values for genesis parameters. App modules must implement aGenerateGenesisState method to generate the initial random GenesisState from a given seed.
See an example from x/auth here.
Once the module’s genesis parameters are generated randomly (or with the key and
values defined in a params file), they are marshaled to JSON format and added
to the app genesis JSON for the simulation.
Random weighted operations
Operations are one of the crucial parts of the Cosmos SDK simulation. They are the transactions (Msg) that are simulated with random field values. The sender of the operation
is also assigned randomly.
Operations on the simulation are simulated using the full transaction cycle of a
ABCI application that exposes the BaseApp.
Using Simsx
Simsx introduces the ability to define aMsgFactory for each of a module’s messages.
These factories are registered in WeightedOperationsX and/or ProposalMsgsX.
weights.Get must match the name of the operation set in the WeightedOperations.
For example, if the module contains an operation op_weight_msg_set_withdraw_address, the name passed to weights.Get should be msg_set_withdraw_address.
See the x/distribution for an example of implementing message factories here
App Simulator manager
The following step is setting up theSimulationManager at the app level. This
is required for the simulation test files in the next step.
ModuleManager and call the RegisterStoreDecoders method.
ModuleManager should be different in the SimulationManager.
Finally, the application should expose the SimulationManager via the following method defined in the AppI interface:
simapp/app.go.
Running Simulations
To run the simulation, use thesimsx runner.
Call simsx.Run to begin simulating with the default seeds, or simsx.RunWithSeeds to provide specific seeds:
app_test.go, app_sim_test.go, etc.).
See the full simapp test file at simapp/sim_test.go.
Simulation test types
The simulation framework provides four test functions, each testing a different failure scenario:TestFullAppSimulation: General simulation mode. Runs the chain and specified operations for a given number of blocks, checking for panics.TestAppImportExport: Exports the initial app state and creates a new app with the exportedgenesis.jsonas input, checking for store inconsistencies between the two.TestAppSimulationAfterImport: Chains two simulations — the first provides its app state to the second. Useful for testing software upgrades or hard-forks from a live chain.TestAppStateDeterminism: Checks that all nodes return the same values in the same order.
Simulator modes
Simulations run in three modes:- Fully random — initial state, module parameters, and simulation parameters are all pseudo-randomly generated.
- From a
genesis.jsonfile — initial state and module parameters are defined by the file. Useful for testing against a known state such as a live network export. - From a
params.jsonfile — initial state is pseudo-randomly generated but module and simulation parameters are set manually. Available parameters are listed here.
Running via go test
Simulations can be run directly withgo test:
Makefile.
Debugging tips
When encountering a simulation failure:- Export app state at the failure height using the
-ExportStatePathflag. - Use
-Verboselogs for a fuller picture of all operations involved. - Try a different
-Seed. If the same error reproduces sooner, you will spend less time on each run. - Reduce
-NumBlocksto isolate what the app state looks like at the block before failure. - Add a
Loggerto operations that are not being logged.