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

test: enable the simulator for the provider module #2005

Merged
merged 33 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
39e5060
Refactor validator set storage
p-offtermatt Jun 25, 2024
7441fe0
Add comment for getTotalPower
p-offtermatt Jun 25, 2024
d9a51fb
Add provider consensus validator set storage
p-offtermatt Jun 25, 2024
96a47d7
Add new MaxProviderConsensusValidators param
p-offtermatt Jun 25, 2024
884a356
Add validation for MaxProviderConsensusValidators
p-offtermatt Jun 25, 2024
356e6e8
Add no_valupdates_staking module
p-offtermatt Jun 25, 2024
b0d3ce0
Add function to get MaxProviderConsensusValidators param
p-offtermatt Jun 26, 2024
5f53dc3
Start returning validators in EndBlock
p-offtermatt Jun 26, 2024
463e370
Fix tests
p-offtermatt Jun 26, 2024
23b4c46
Revert cosmetic change
p-offtermatt Jun 26, 2024
8b57495
Revert cosmetic changes
p-offtermatt Jun 26, 2024
b4ed21a
Revert formatting
p-offtermatt Jun 26, 2024
bc69f20
Add genutil replacer module
p-offtermatt Jun 26, 2024
ca84368
Revert formatting
p-offtermatt Jun 26, 2024
eb6f00f
Revert formatting in tests/integration
p-offtermatt Jun 26, 2024
8f8ff96
Revert minor formatting
p-offtermatt Jun 26, 2024
4e8b917
Fix type
p-offtermatt Jun 27, 2024
af1b7d4
Change wrapped staking to conform to EndBlocker interface
p-offtermatt Jun 27, 2024
62dfd1e
Fix typo
p-offtermatt Jun 27, 2024
49a6e04
Revert "Fix typo"
p-offtermatt Jun 27, 2024
cc1185d
Add e2e test for inactive vals
p-offtermatt Jun 27, 2024
732e35d
Start fixing e2e test
p-offtermatt Jun 27, 2024
c07a765
Revert formatting changes
p-offtermatt Jul 2, 2024
1cf874d
Remove more formatting
p-offtermatt Jul 2, 2024
9d0c9b7
Revert extra formatting
p-offtermatt Jul 2, 2024
4a5b80c
Re-wire provider/app.go to use wrapped modules
p-offtermatt Jul 2, 2024
fda55c4
Remove consumer rewards check
p-offtermatt Jul 2, 2024
f576f84
Add simulator test
p-offtermatt Jul 2, 2024
11b1585
Add randomly generated parameters for provider in sim
p-offtermatt Jul 3, 2024
beac286
Add invariant
p-offtermatt Jul 3, 2024
10866bd
Add simulation to Makefile and github workflow
p-offtermatt Jul 3, 2024
3af7e99
Use simcli instead of just passing true
p-offtermatt Jul 4, 2024
22de291
Merge branch 'feat/inactive-vals-v50' into ph/simulator
p-offtermatt Jul 15, 2024
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
44 changes: 44 additions & 0 deletions .github/workflows/simulation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Simulation
on:
workflow_call:
pull_request:
merge_group:
push:
branches:
- main
- release/v*
- feat/*

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}-tests
cancel-in-progress: true

jobs:
simulation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/[email protected]
id: git_diff
with:
PATTERNS: |
**/*.go
go.mod
go.sum
**/go.mod
**/go.sum
**/Makefile
Makefile
- name: simulation test
if: env.GIT_DIFF
run: |
make sim-full
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ verify-models:
../run_invariants.sh


###############################################################################
### Simulation tests ###

# Run a full simulation test
sim-full:
cd app/provider;\
go test -mod=readonly -run=^TestFullAppSimulation$ -Enabled=true -NumBlocks=500 -BlockSize=200 -Commit=true -timeout 24h github.com/cosmos/interchain-security/v5/app/provider -v

###############################################################################
### Linting ###
Expand Down
19 changes: 16 additions & 3 deletions app/provider/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import (
authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
"github.com/cosmos/cosmos-sdk/x/auth/posthandler"
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
Expand Down Expand Up @@ -352,9 +353,7 @@ func New(
// Remove the ConsumerRewardsPool from the group of blocked recipient addresses in bank
// this is required for the provider chain to be able to receive tokens from
// the consumer chain
bankBlockedAddrs := app.ModuleAccountAddrs()
delete(bankBlockedAddrs, authtypes.NewModuleAddress(
providertypes.ConsumerRewardsPool).String())
bankBlockedAddrs := BankBlockedAddrs(app)

app.BankKeeper = bankkeeper.NewBaseKeeper(
appCodec,
Expand Down Expand Up @@ -679,6 +678,13 @@ func New(
}

// create the simulation manager and define the order of the modules for deterministic simulations
overrideModules := map[string]module.AppModuleSimulation{
authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)),
}
app.sm = module.NewSimulationManagerFromAppModules(app.MM.Modules, overrideModules)

// register the store decoders for simulation tests
app.sm.RegisterStoreDecoders()

// Note this upgrade handler is just an example and may not be exactly what you need to implement.
// See https://docs.cosmos.network/v0.45/building-modules/upgrade.html
Expand Down Expand Up @@ -780,6 +786,13 @@ func New(
return app
}

func BankBlockedAddrs(app *App) map[string]bool {
bankBlockedAddrs := app.ModuleAccountAddrs()
delete(bankBlockedAddrs, authtypes.NewModuleAddress(
providertypes.ConsumerRewardsPool).String())
return bankBlockedAddrs
}

// Name returns the name of the App
func (app *App) Name() string { return app.BaseApp.Name() }

Expand Down
85 changes: 85 additions & 0 deletions app/provider/sim_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package app_test

import (
"os"
"testing"

"cosmossdk.io/store"
"github.com/stretchr/testify/require"

"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"
"github.com/cosmos/cosmos-sdk/x/simulation"
simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"

simtypes "github.com/cosmos/cosmos-sdk/types/simulation"

providerapp "github.com/cosmos/interchain-security/v5/app/provider"
)

func init() {
simcli.GetSimulatorFlags()
}

// 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())
}

// fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
// an IAVLStore for faster simulation speed.
func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
bapp.SetFauxMerkleMode()
}

func TestFullAppSimulation(t *testing.T) {
config := simcli.NewConfigFromFlags()
config.ChainID = "provi"

db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "leveldb-app-sim", "Simulation", simcli.FlagVerboseValue, simcli.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))
}()
Comment on lines +48 to +51
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handle potential errors in deferred functions.

The deferred functions should handle potential errors from db.Close() and os.RemoveAll(dir) to ensure proper resource cleanup.

defer func() {
  if err := db.Close(); err != nil {
    t.Errorf("failed to close database: %v", err)
  }
  if err := os.RemoveAll(dir); err != nil {
    t.Errorf("failed to remove directory: %v", err)
  }
}()
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
defer func() {
require.NoError(t, db.Close())
require.NoError(t, os.RemoveAll(dir))
}()
defer func() {
if err := db.Close(); err != nil {
t.Errorf("failed to close database: %v", err)
}
if err := os.RemoveAll(dir); err != nil {
t.Errorf("failed to remove directory: %v", err)
}
}()


appOptions := make(simtestutil.AppOptionsMap, 0)
appOptions[flags.FlagHome] = providerapp.DefaultNodeHome
appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue

app := providerapp.New(logger, db, nil, true, appOptions, fauxMerkleModeOpt, interBlockCacheOpt(), baseapp.SetChainID("provi"))
require.Equal(t, "interchain-security-p", app.Name())

encoding := providerapp.MakeTestEncodingConfig()

genesisState := providerapp.NewDefaultGenesisState(encoding.Codec)

// run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
t,
os.Stdout,
app.BaseApp,
simtestutil.AppStateFn(encoding.Codec, app.SimulationManager(), genesisState),
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simtestutil.SimulationOperations(app, app.AppCodec(), config),
providerapp.BankBlockedAddrs(app),
config,
app.AppCodec(),
)

// export state and simParams before the simulation error is checked
err = simtestutil.CheckExportSimulation(app, config, simParams)
require.NoError(t, err)
require.NoError(t, simErr)

if config.Commit {
simtestutil.PrintStats(db)
}
}
32 changes: 32 additions & 0 deletions x/ccv/provider/keeper/invariants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package keeper

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
types "github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
)

// RegisterInvariants registers all staking invariants
func RegisterInvariants(ir sdk.InvariantRegistry, k *Keeper) {
ir.RegisterRoute(types.ModuleName, "max-provider-validators",
MaxProviderConsensusValidatorsInvariant(k))
}

// MaxProviderConsensusValidatorsInvariant checks that the number of provider consensus validators
// is less than or equal to the maximum number of provider consensus validators
func MaxProviderConsensusValidatorsInvariant(k *Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
params := k.GetParams(ctx)
maxProviderConsensusValidators := params.MaxProviderConsensusValidators

consensusValidators := k.GetLastProviderConsensusValSet(ctx)
if int64(len(consensusValidators)) > maxProviderConsensusValidators {
return sdk.FormatInvariant(types.ModuleName, "max-provider-validators",
fmt.Sprintf("number of provider consensus validators: %d, exceeds max: %d",
len(consensusValidators), maxProviderConsensusValidators)), true
}

return "", false
}
}
6 changes: 4 additions & 2 deletions x/ccv/provider/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/cosmos/interchain-security/v5/x/ccv/provider/client/cli"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/migrations"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/simulation"
providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
)

Expand Down Expand Up @@ -115,8 +116,8 @@ func NewAppModule(k *keeper.Keeper, paramSpace paramtypes.Subspace) AppModule {
}

// RegisterInvariants implements the AppModule interface
func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
// TODO
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
keeper.RegisterInvariants(ir, am.keeper)
}

// RegisterServices registers module services.
Expand Down Expand Up @@ -191,6 +192,7 @@ func (am AppModule) EndBlock(ctx context.Context) ([]abci.ValidatorUpdate, error

// GenerateGenesisState creates a randomized GenState of the transfer module.
func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}

// RegisterStoreDecoder registers a decoder for provider module's types
Expand Down
44 changes: 44 additions & 0 deletions x/ccv/provider/simulation/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package simulation

import (
"encoding/json"
"fmt"
"math/rand"

"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
)

// Simulation parameter constants
const (
// only includes params that make sense even with a single
maxProviderConsensusValidators = "max_provider_consensus_validators"
)

// genMaxProviderConsensusValidators returns randomized maxProviderConsensusValidators
func genMaxProviderConsensusValidators(r *rand.Rand) int64 {
return int64(r.Intn(250) + 1)
}

// RandomizedGenState generates a random GenesisState for staking
func RandomizedGenState(simState *module.SimulationState) {
// params
var (
maxProviderConsensusVals int64
)

simState.AppParams.GetOrGenerate(maxProviderConsensusValidators, &maxProviderConsensusVals, simState.Rand, func(r *rand.Rand) { maxProviderConsensusVals = genMaxProviderConsensusValidators(r) })

providerParams := types.DefaultParams()
providerParams.MaxProviderConsensusValidators = maxProviderConsensusVals

providerGenesis := types.DefaultGenesisState()
providerGenesis.Params = providerParams

bz, err := json.MarshalIndent(&providerGenesis.Params, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("Selected randomly generated provider parameters:\n%s\n", bz)
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(providerGenesis)
}
Loading