From e08f5da2436f18e79b293ade011ee03b92bbd8ce Mon Sep 17 00:00:00 2001 From: marbar3778 Date: Tue, 17 Sep 2024 12:48:45 +0200 Subject: [PATCH 1/4] minor cleanup and fixing of links --- docs/build/building-modules/14-simulator.md | 24 +++++++------ docs/learn/advanced/12-simulation.md | 40 +++++++-------------- simsx/README.md | 13 ++++--- types/simulation/collections.go | 1 + 4 files changed, 35 insertions(+), 43 deletions(-) diff --git a/docs/build/building-modules/14-simulator.md b/docs/build/building-modules/14-simulator.md index ca6f5ae2e67f..966df4cb8952 100644 --- a/docs/build/building-modules/14-simulator.md +++ b/docs/build/building-modules/14-simulator.md @@ -38,6 +38,8 @@ and then unmarshals the value from the `KVPair` to the type provided. You can use the example [here](https://github.com/cosmos/cosmos-sdk/blob/main/x/distribution/simulation/decoder.go) from the distribution module to implement your store decoders. +If the module uses the `collections` package, you can use the example [here](https://github.com/cosmos/cosmos-sdk/blob/23cf89cce1882ba9c8280e64735ae200504bfdce/x/bank/module.go#L166) from the Bank module to implement your store decoders. + ### Randomized genesis The simulator tests different scenarios and values for genesis parameters @@ -61,33 +63,33 @@ Operations on the simulation are simulated using the full [transaction cycle](.. Shown below is how weights are set: ```go reference -https://github.com/cosmos/cosmos-sdk/blob/release/v0.50.x/x/staking/simulation/operations.go#L19-L86 +https://github.com/cosmos/cosmos-sdk/blob/23cf89cce1882ba9c8280e64735ae200504bfdce/x/staking/depinject.go#L144-L154 ``` As you can see, the weights are predefined in this case. Options exist to override this behavior with different weights. One option is to use `*rand.Rand` to define a random weight for the operation, or you can inject your own predefined weights. -Here is how one can override the above package `simappparams`. - -```go reference -https://github.com/cosmos/cosmos-sdk/blob/release/v0.51.x/Makefile#L292-L334 -``` - The SDK simulations can be executed like normal tests in Go from the shell or within an IDE. Make sure that you pass the `-tags='sims` parameter to enable them and other params that make sense for your scenario. +```go reference +https://github.com/cosmos/cosmos-sdk/blob/23cf89cce1882ba9c8280e64735ae200504bfdce/scripts/build/simulations.mk#L19 +``` ### Random proposal contents Randomized governance proposals are also supported on the Cosmos SDK simulator. Each -module must define the governance proposal `Content`s that they expose and register -them to be used on the parameters. +module must register the message to be used for governance proposals. + +```go reference +https://github.com/cosmos/cosmos-sdk/blob/23cf89cce1882ba9c8280e64735ae200504bfdce/x/staking/depinject.go#L139-L142 +``` ## Registering simulation functions Now that all the required functions are defined, we need to integrate them into the module pattern within the `module.go`: ```go reference -https://github.com/cosmos/cosmos-sdk/blob/release/v0.50.x/x/distribution/module.go#L180-L203 +https://github.com/cosmos/cosmos-sdk/blob/23cf89cce1882ba9c8280e64735ae200504bfdce/x/staking/depinject.go#L127-L154 ``` ## App Simulator manager @@ -133,5 +135,5 @@ The simulations provide deterministic behaviour already. The integration with th can be done at a high level with the deterministic pseudo random number generator where the fuzzer provides varying numbers. ```go reference -https://github.com/cosmos/cosmos-sdk/blob/release/v0.51.x/Makefile#L352-L355 +https://github.com/cosmos/cosmos-sdk/blob/23cf89cce1882ba9c8280e64735ae200504bfdce/scripts/build/simulations.mk#L80-L84 ``` diff --git a/docs/learn/advanced/12-simulation.md b/docs/learn/advanced/12-simulation.md index dfbcddd0d29f..1198353c8ddb 100644 --- a/docs/learn/advanced/12-simulation.md +++ b/docs/learn/advanced/12-simulation.md @@ -7,37 +7,26 @@ sidebar_position: 1 The Cosmos SDK offers a full fledged simulation framework to fuzz test every message defined by a module. -On the Cosmos SDK, this functionality is provided by [`SimApp`](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/simapp/app_v2.go), which is a -`Baseapp` application that is used for running the [`simulation`](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/simulation) module. -This module defines all the simulation logic as well as the operations for -randomized parameters like accounts, balances etc. +On the Cosmos SDK, this functionality is provided by [`SimApp`](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/simapp/app_v2.go), which is a `Baseapp` application that is used for running the [`simulation`](https://github.com/cosmos/cosmos-sdk/blob/23cf89cce1882ba9c8280e64735ae200504bfdce/simsx/README.md#L1) package. This package defines all the simulation logic as well as the operations for randomized parameters like accounts, balances etc. ## Goals -The blockchain simulator 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 when a failure was found. +The blockchain simulator 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 when a failure was found. -Its main difference with integration testing is that the simulator app allows -you to pass parameters to customize the chain that's being simulated. -This comes in handy when trying to reproduce bugs that were generated in the -provided operations (randomized or not). +Its main difference with integration testing is that the simulator app allows you to pass parameters to customize the chain that's being simulated. This comes in handy when trying to reproduce bugs that were generated in the provided operations (randomized or not). ## Simulation commands The simulation app has different commands, each of which tests a different failure type: -* `AppImportExport`: The simulator exports the initial app state and then it - creates a new app with the exported `genesis.json` as an input, checking for - inconsistencies between the stores. +* `AppImportExport`: The simulator exports the initial app state and then it creates a new app with the exported `genesis.json` as an input, checking for inconsistencies between the stores. * `AppSimulationAfterImport`: Queues two simulations together. The first one provides the app state (_i.e_ genesis) to the second. Useful to test software upgrades or hard-forks from a live chain. * `AppStateDeterminism`: Checks that all the nodes return the same values, in the same order. -* `BenchmarkInvariants`: Analysis of the performance of running all modules' invariants (_i.e_ sequentially runs a [benchmark](https://pkg.go.dev/testing/#hdr-Benchmarks) test). An invariant checks for - differences between the values that are on the store and the passive tracker. Eg: total coins held by accounts vs total supply tracker. +* `BenchmarkInvariants`: Analysis of the performance of running all modules' invariants (_i.e_ sequentially runs a [benchmark](https://pkg.go.dev/testing/#hdr-Benchmarks) test). An invariant checks for differences between the values that are on the store and the passive tracker. Eg: total coins held by accounts vs total supply tracker. * `FullAppSimulation`: General simulation mode. Runs the chain and the specified operations for a given number of blocks. Tests that there're no `panics` on the simulation. It does also run invariant checks on every `Period` but they are not benchmarked. +* `FuzzFullAppSimulation`: Runs general simulation mode with the [go fuzzer](https://go.dev/doc/security/fuzz/) to find panics. +* `AppStateDeterminism`: Runs a few seeds many times to test that the apphash is deterministic across the runs. Each simulation must receive a set of inputs (_i.e_ flags) such as the number of blocks that the simulation is run, seed, block size, etc. @@ -47,23 +36,18 @@ Check the full list of flags [here](https://github.com/cosmos/cosmos-sdk/blob/v0 In addition to the various inputs and commands, the simulator runs in three modes: -1. Completely random where the initial state, module parameters and simulation - parameters are **pseudo-randomly generated**. -2. From a `genesis.json` file where the initial state and the module parameters are defined. - This mode is helpful for running simulations on a known state such as a live network export where a new (mostly likely breaking) version of the application needs to be tested. -3. From a `params.json` file where the initial state is pseudo-randomly generated but the module and simulation parameters can be provided manually. - This allows for a more controlled and deterministic simulation setup while allowing the state space to still be pseudo-randomly simulated. - The list of available parameters are listed [here](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/simulation/client/cli/flags.go#L59-L78). +1. Completely random where the initial state, module parameters and simulation parameters are **pseudo-randomly generated**. +2. From a `genesis.json` file where the initial state and the module parameters are defined. This mode is helpful for running simulations on a known state such as a live network export where a new (mostly likely breaking) version of the application needs to be tested. +3. From a `params.json` file where the initial state is pseudo-randomly generated but the module and simulation parameters can be provided manually. This allows for a more controlled and deterministic simulation setup while allowing the state space to still be pseudo-randomly simulated. The list of available parameters are listed [here](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/simulation/client/cli/flags.go#L59-L78). :::tip -These modes are not mutually exclusive. So you can for example run a randomly -generated genesis state (`1`) with manually generated simulation params (`3`). +These modes are not mutually exclusive. So you can for example run a randomly generated genesis state (`1`) with manually generated simulation params (`3`). ::: ## Usage This is a general example of how simulations are run. For more specific examples -check the Cosmos SDK [Makefile](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/Makefile#L282-L318). +check the Cosmos SDK [Makefile](https://github.com/cosmos/cosmos-sdk/blob/23cf89cce1882ba9c8280e64735ae200504bfdce/scripts/build/simulations.mk#L1-L104). ```bash $ go test -mod=readonly github.com/cosmos/cosmos-sdk/simapp \ diff --git a/simsx/README.md b/simsx/README.md index fe1cc2058113..3e2d9146ce42 100644 --- a/simsx/README.md +++ b/simsx/README.md @@ -3,9 +3,10 @@ This package introduces some new helper types to simplify message construction for simulations (sims). The focus is on better dev UX for new message factories. Technically, they are adapters that build upon the existing sims framework. -#### * [Message factory](https://github.com/cosmos/cosmos-sdk/blob/main/simsx/msg_factory.go) +## [Message factory](https://github.com/cosmos/cosmos-sdk/blob/main/simsx/msg_factory.go) Simple functions as factories for dedicated sdk.Msgs. They have access to the context, reporter and test data environment. For example: + ```go func MsgSendFactory() simsx.SimMsgFactoryFn[*types.MsgSend] { return func(ctx context.Context, testData *simsx.ChainDataSource, reporter simsx.SimulationReporter) ([]simsx.SimAccount, *types.MsgSend) { @@ -17,9 +18,10 @@ func MsgSendFactory() simsx.SimMsgFactoryFn[*types.MsgSend] { } ``` -#### * [Sims registry](https://github.com/cosmos/cosmos-sdk/blob/main/simsx/registry.go) +## [Sims registry](https://github.com/cosmos/cosmos-sdk/blob/main/simsx/registry.go) A new helper to register message factories with a default weight value. They can be overwritten by a parameters file as before. The registry is passed to the AppModule type. For example: + ```go func (am AppModule) WeightedOperationsX(weights simsx.WeightSource, reg simsx.Registry) { reg.Add(weights.Get("msg_send", 100), simulation.MsgSendFactory()) @@ -27,16 +29,19 @@ func (am AppModule) WeightedOperationsX(weights simsx.WeightSource, reg simsx.Re } ``` -#### * [Reporter](https://github.com/cosmos/cosmos-sdk/blob/main/simsx/reporter.go) +## [Reporter](https://github.com/cosmos/cosmos-sdk/blob/main/simsx/reporter.go) + The reporter is a flow control structure that can be used in message factories to skip execution at any point. The idea is similar to the testing.T Skip in Go stdlib. Internally, it converts skip, success and failure events to legacy sim messages. The reporter also provides some capability to print an execution summary. It is also used to interact with the test data environment to not have errors checked all the time. Message factories may want to abort early via + ```go if reporter.IsSkipped() { return nil, nil } ``` -#### * [Test data environment](https://github.com/cosmos/cosmos-sdk/blob/main/simsx/environment.go) +## [Test data environment](https://github.com/cosmos/cosmos-sdk/blob/main/simsx/environment.go) + The test data environment provides simple access to accounts and other test data used in most message factories. It also encapsulates some app internals like bank keeper or address codec. diff --git a/types/simulation/collections.go b/types/simulation/collections.go index 950068fc4835..f3c749bb25a7 100644 --- a/types/simulation/collections.go +++ b/types/simulation/collections.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/kv" ) +// NewStoreDecoderFuncFromCollectionsSchema returns a function that decodes two kv pairs when the module fully uses collections func NewStoreDecoderFuncFromCollectionsSchema(schema collections.Schema) func(kvA, kvB kv.Pair) string { colls := schema.ListCollections() prefixes := make([][]byte, len(colls)) From 04db3be706abe2a752dc04c684dec071715faede Mon Sep 17 00:00:00 2001 From: marbar3778 Date: Tue, 17 Sep 2024 12:56:52 +0200 Subject: [PATCH 2/4] remove distribution decoders --- x/distribution/module.go | 2 +- x/distribution/simulation/decoder.go | 68 ----------------------- x/distribution/simulation/decoder_test.go | 63 --------------------- 3 files changed, 1 insertion(+), 132 deletions(-) delete mode 100644 x/distribution/simulation/decoder.go delete mode 100644 x/distribution/simulation/decoder_test.go diff --git a/x/distribution/module.go b/x/distribution/module.go index eb7de978c6d1..d8655be93370 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -169,7 +169,7 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { // RegisterStoreDecoder registers a decoder for distribution module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { - sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc) + sdr[types.StoreKey] = simtypes.NewStoreDecoderFuncFromCollectionsSchema(am.keeper.Schema) } // ProposalMsgsX returns msgs used for governance proposals for simulations. diff --git a/x/distribution/simulation/decoder.go b/x/distribution/simulation/decoder.go deleted file mode 100644 index 0373ce40d87f..000000000000 --- a/x/distribution/simulation/decoder.go +++ /dev/null @@ -1,68 +0,0 @@ -package simulation - -import ( - "bytes" - "fmt" - - "cosmossdk.io/x/distribution/types" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/kv" -) - -// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's -// Value to the corresponding distribution type. -func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { - return func(kvA, kvB kv.Pair) string { - switch { - case bytes.Equal(kvA.Key[:1], types.FeePoolKey): - var feePoolA, feePoolB types.FeePool - cdc.MustUnmarshal(kvA.Value, &feePoolA) - cdc.MustUnmarshal(kvB.Value, &feePoolB) - return fmt.Sprintf("%v\n%v", feePoolA, feePoolB) - - case bytes.Equal(kvA.Key[:1], types.ValidatorOutstandingRewardsPrefix): - var rewardsA, rewardsB types.ValidatorOutstandingRewards - cdc.MustUnmarshal(kvA.Value, &rewardsA) - cdc.MustUnmarshal(kvB.Value, &rewardsB) - return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) - - case bytes.Equal(kvA.Key[:1], types.DelegatorWithdrawAddrPrefix): - return fmt.Sprintf("%v\n%v", sdk.AccAddress(kvA.Value), sdk.AccAddress(kvB.Value)) - - case bytes.Equal(kvA.Key[:1], types.DelegatorStartingInfoPrefix): - var infoA, infoB types.DelegatorStartingInfo - cdc.MustUnmarshal(kvA.Value, &infoA) - cdc.MustUnmarshal(kvB.Value, &infoB) - return fmt.Sprintf("%v\n%v", infoA, infoB) - - case bytes.Equal(kvA.Key[:1], types.ValidatorHistoricalRewardsPrefix): - var rewardsA, rewardsB types.ValidatorHistoricalRewards - cdc.MustUnmarshal(kvA.Value, &rewardsA) - cdc.MustUnmarshal(kvB.Value, &rewardsB) - return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) - - case bytes.Equal(kvA.Key[:1], types.ValidatorCurrentRewardsPrefix): - var rewardsA, rewardsB types.ValidatorCurrentRewards - cdc.MustUnmarshal(kvA.Value, &rewardsA) - cdc.MustUnmarshal(kvB.Value, &rewardsB) - return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) - - case bytes.Equal(kvA.Key[:1], types.ValidatorAccumulatedCommissionPrefix): - var commissionA, commissionB types.ValidatorAccumulatedCommission - cdc.MustUnmarshal(kvA.Value, &commissionA) - cdc.MustUnmarshal(kvB.Value, &commissionB) - return fmt.Sprintf("%v\n%v", commissionA, commissionB) - - case bytes.Equal(kvA.Key[:1], types.ValidatorSlashEventPrefix): - var eventA, eventB types.ValidatorSlashEvent - cdc.MustUnmarshal(kvA.Value, &eventA) - cdc.MustUnmarshal(kvB.Value, &eventB) - return fmt.Sprintf("%v\n%v", eventA, eventB) - - default: - panic(fmt.Sprintf("invalid distribution key prefix %X", kvA.Key[:1])) - } - } -} diff --git a/x/distribution/simulation/decoder_test.go b/x/distribution/simulation/decoder_test.go deleted file mode 100644 index 52b4d1b4886f..000000000000 --- a/x/distribution/simulation/decoder_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package simulation_test - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - "cosmossdk.io/math" - "cosmossdk.io/x/distribution" - "cosmossdk.io/x/distribution/simulation" - "cosmossdk.io/x/distribution/types" - - codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/kv" - moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" -) - -var ( - delPk1 = ed25519.GenPrivKey().PubKey() - valAddr1 = sdk.ValAddress(delPk1.Address()) -) - -func TestDecodeDistributionStore(t *testing.T) { - encodingConfig := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, distribution.AppModule{}) - cdc := encodingConfig.Codec - - dec := simulation.NewDecodeStore(cdc) - - decCoins := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyOneDec())} - feePool := types.InitialFeePool() - feePool.DecimalPool = decCoins - slashEvent := types.NewValidatorSlashEvent(10, math.LegacyOneDec()) - - kvPairs := kv.Pairs{ - Pairs: []kv.Pair{ - {Key: types.FeePoolKey, Value: cdc.MustMarshal(&feePool)}, - {Key: types.GetValidatorSlashEventKeyPrefix(valAddr1, 13), Value: cdc.MustMarshal(&slashEvent)}, - {Key: []byte{0x99}, Value: []byte{0x99}}, - }, - } - - tests := []struct { - name string - expectedLog string - }{ - {"FeePool", fmt.Sprintf("%v\n%v", feePool, feePool)}, - {"ValidatorSlashEvent", fmt.Sprintf("%v\n%v", slashEvent, slashEvent)}, - {"other", ""}, - } - for i, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - switch i { - case len(tests) - 1: - require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name) - default: - require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name) - } - }) - } -} From 51b117eec924b485af38586cee53a789dc8a7143 Mon Sep 17 00:00:00 2001 From: marbar3778 Date: Tue, 17 Sep 2024 14:04:37 +0200 Subject: [PATCH 3/4] revert removal of decoders --- x/distribution/module.go | 2 +- x/distribution/simulation/decoder.go | 68 +++++++++++++++++++++++ x/distribution/simulation/decoder_test.go | 63 +++++++++++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 x/distribution/simulation/decoder.go create mode 100644 x/distribution/simulation/decoder_test.go diff --git a/x/distribution/module.go b/x/distribution/module.go index d8655be93370..eb7de978c6d1 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -169,7 +169,7 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { // RegisterStoreDecoder registers a decoder for distribution module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { - sdr[types.StoreKey] = simtypes.NewStoreDecoderFuncFromCollectionsSchema(am.keeper.Schema) + sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc) } // ProposalMsgsX returns msgs used for governance proposals for simulations. diff --git a/x/distribution/simulation/decoder.go b/x/distribution/simulation/decoder.go new file mode 100644 index 000000000000..0373ce40d87f --- /dev/null +++ b/x/distribution/simulation/decoder.go @@ -0,0 +1,68 @@ +package simulation + +import ( + "bytes" + "fmt" + + "cosmossdk.io/x/distribution/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/kv" +) + +// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's +// Value to the corresponding distribution type. +func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { + return func(kvA, kvB kv.Pair) string { + switch { + case bytes.Equal(kvA.Key[:1], types.FeePoolKey): + var feePoolA, feePoolB types.FeePool + cdc.MustUnmarshal(kvA.Value, &feePoolA) + cdc.MustUnmarshal(kvB.Value, &feePoolB) + return fmt.Sprintf("%v\n%v", feePoolA, feePoolB) + + case bytes.Equal(kvA.Key[:1], types.ValidatorOutstandingRewardsPrefix): + var rewardsA, rewardsB types.ValidatorOutstandingRewards + cdc.MustUnmarshal(kvA.Value, &rewardsA) + cdc.MustUnmarshal(kvB.Value, &rewardsB) + return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) + + case bytes.Equal(kvA.Key[:1], types.DelegatorWithdrawAddrPrefix): + return fmt.Sprintf("%v\n%v", sdk.AccAddress(kvA.Value), sdk.AccAddress(kvB.Value)) + + case bytes.Equal(kvA.Key[:1], types.DelegatorStartingInfoPrefix): + var infoA, infoB types.DelegatorStartingInfo + cdc.MustUnmarshal(kvA.Value, &infoA) + cdc.MustUnmarshal(kvB.Value, &infoB) + return fmt.Sprintf("%v\n%v", infoA, infoB) + + case bytes.Equal(kvA.Key[:1], types.ValidatorHistoricalRewardsPrefix): + var rewardsA, rewardsB types.ValidatorHistoricalRewards + cdc.MustUnmarshal(kvA.Value, &rewardsA) + cdc.MustUnmarshal(kvB.Value, &rewardsB) + return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) + + case bytes.Equal(kvA.Key[:1], types.ValidatorCurrentRewardsPrefix): + var rewardsA, rewardsB types.ValidatorCurrentRewards + cdc.MustUnmarshal(kvA.Value, &rewardsA) + cdc.MustUnmarshal(kvB.Value, &rewardsB) + return fmt.Sprintf("%v\n%v", rewardsA, rewardsB) + + case bytes.Equal(kvA.Key[:1], types.ValidatorAccumulatedCommissionPrefix): + var commissionA, commissionB types.ValidatorAccumulatedCommission + cdc.MustUnmarshal(kvA.Value, &commissionA) + cdc.MustUnmarshal(kvB.Value, &commissionB) + return fmt.Sprintf("%v\n%v", commissionA, commissionB) + + case bytes.Equal(kvA.Key[:1], types.ValidatorSlashEventPrefix): + var eventA, eventB types.ValidatorSlashEvent + cdc.MustUnmarshal(kvA.Value, &eventA) + cdc.MustUnmarshal(kvB.Value, &eventB) + return fmt.Sprintf("%v\n%v", eventA, eventB) + + default: + panic(fmt.Sprintf("invalid distribution key prefix %X", kvA.Key[:1])) + } + } +} diff --git a/x/distribution/simulation/decoder_test.go b/x/distribution/simulation/decoder_test.go new file mode 100644 index 000000000000..52b4d1b4886f --- /dev/null +++ b/x/distribution/simulation/decoder_test.go @@ -0,0 +1,63 @@ +package simulation_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/math" + "cosmossdk.io/x/distribution" + "cosmossdk.io/x/distribution/simulation" + "cosmossdk.io/x/distribution/types" + + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/kv" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" +) + +var ( + delPk1 = ed25519.GenPrivKey().PubKey() + valAddr1 = sdk.ValAddress(delPk1.Address()) +) + +func TestDecodeDistributionStore(t *testing.T) { + encodingConfig := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, distribution.AppModule{}) + cdc := encodingConfig.Codec + + dec := simulation.NewDecodeStore(cdc) + + decCoins := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyOneDec())} + feePool := types.InitialFeePool() + feePool.DecimalPool = decCoins + slashEvent := types.NewValidatorSlashEvent(10, math.LegacyOneDec()) + + kvPairs := kv.Pairs{ + Pairs: []kv.Pair{ + {Key: types.FeePoolKey, Value: cdc.MustMarshal(&feePool)}, + {Key: types.GetValidatorSlashEventKeyPrefix(valAddr1, 13), Value: cdc.MustMarshal(&slashEvent)}, + {Key: []byte{0x99}, Value: []byte{0x99}}, + }, + } + + tests := []struct { + name string + expectedLog string + }{ + {"FeePool", fmt.Sprintf("%v\n%v", feePool, feePool)}, + {"ValidatorSlashEvent", fmt.Sprintf("%v\n%v", slashEvent, slashEvent)}, + {"other", ""}, + } + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + switch i { + case len(tests) - 1: + require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name) + default: + require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name) + } + }) + } +} From 1120b96d6528c67fa1421062f8d6c4b3eb3e4c8b Mon Sep 17 00:00:00 2001 From: Marko Date: Wed, 18 Sep 2024 11:15:49 +0200 Subject: [PATCH 4/4] Update docs/learn/advanced/12-simulation.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Julián Toledano --- docs/learn/advanced/12-simulation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/learn/advanced/12-simulation.md b/docs/learn/advanced/12-simulation.md index 1198353c8ddb..c30d398c32e9 100644 --- a/docs/learn/advanced/12-simulation.md +++ b/docs/learn/advanced/12-simulation.md @@ -38,7 +38,7 @@ In addition to the various inputs and commands, the simulator runs in three mode 1. Completely random where the initial state, module parameters and simulation parameters are **pseudo-randomly generated**. 2. From a `genesis.json` file where the initial state and the module parameters are defined. This mode is helpful for running simulations on a known state such as a live network export where a new (mostly likely breaking) version of the application needs to be tested. -3. From a `params.json` file where the initial state is pseudo-randomly generated but the module and simulation parameters can be provided manually. This allows for a more controlled and deterministic simulation setup while allowing the state space to still be pseudo-randomly simulated. The list of available parameters are listed [here](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/simulation/client/cli/flags.go#L59-L78). +3. From a `params.json` file where the initial state is pseudo-randomly generated but the module and simulation parameters can be provided manually. This allows for a more controlled and deterministic simulation setup while allowing the state space to still be pseudo-randomly simulated. All available parameters are listed [here](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/simulation/client/cli/flags.go#L59-L78). :::tip These modes are not mutually exclusive. So you can for example run a randomly generated genesis state (`1`) with manually generated simulation params (`3`).