Skip to content

Commit

Permalink
Added non-determinism simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
mikluke committed Nov 21, 2023
1 parent a9e2f73 commit 6bf35f8
Show file tree
Hide file tree
Showing 24 changed files with 945 additions and 288 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ test:
@echo "Running tests"
$(V)go test -mod=readonly $(shell go list ./... | grep -v '/simulation')

.PHONY: test-determinism
test-determinism:
@echo "Running simulation"
$(V)go test -mod=readonly --tags=simulation -v -run TestAppStateDeterminism ./app

.PHONY: lint
lint:
@echo "Running linter"
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,12 @@ make generate

#### Run tests
```shell
make test
```

Also you can run non-determinism simulation
```shell
make test-determinism
```

#### Run linter
Expand Down
4 changes: 2 additions & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ func New(
app.BankKeeper,
authtypes.FeeCollectorName,
)
scorumModule := scorum.NewAppModule(appCodec, app.ScorumKeeper, app.BankKeeper)
scorumModule := scorum.NewAppModule(appCodec, app.ScorumKeeper, app.AccountKeeper, app.BankKeeper)

app.AviatrixKeeper = aviatrixkeeper.NewKeeper(
appCodec,
Expand All @@ -507,7 +507,7 @@ func New(
app.NftKeeper,
app.ScorumKeeper,
)
aviatrixModule := aviatrix.NewAppModule(appCodec, app.AviatrixKeeper)
aviatrixModule := aviatrix.NewAppModule(appCodec, app.AviatrixKeeper, app.ScorumKeeper, app.NftKeeper, app.AccountKeeper, app.BankKeeper)

govRouter := govv1beta1.NewRouter()
govRouter.
Expand Down
167 changes: 94 additions & 73 deletions app/simulation_test.go
Original file line number Diff line number Diff line change
@@ -1,93 +1,114 @@
//go:build simulation

package app_test

import (
"encoding/json"
"fmt"
"math/rand"
"os"
"testing"
"time"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/simapp/helpers"
"github.com/cosmos/cosmos-sdk/store"
simulationtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"

"github.com/scorum/cosmos-network/app"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
)

func init() {
simapp.GetSimulatorFlags()
}

var defaultConsensusParams = &abci.ConsensusParams{
Block: &abci.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,
},
},
// 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())
}

// BenchmarkSimulation run the chain simulation
// Running using starport command:
// `ignite chain simulate -v --numBlocks 200 --blockSize 50`
// Running as go benchmark test:
// `go test -benchmem -run=^$ -bench ^BenchmarkSimulation ./app -NumBlocks=200 -BlockSize 50 -Commit=true -Verbose=true -Enabled=true`
func BenchmarkSimulation(b *testing.B) {
simapp.FlagEnabledValue = true
simapp.FlagCommitValue = true

config, db, dir, logger, _, err := simapp.SetupSimulation("goleveldb-app-sim", "Simulation")
require.NoError(b, err, "simulation setup failed")

b.Cleanup(func() {
db.Close()
err = os.RemoveAll(dir)
require.NoError(b, err)
})

encoding := app.MakeEncodingConfig()

app := app.New(
logger,
db,
nil,
true,
map[int64]bool{},
app.DefaultNodeHome,
0,
encoding,
simapp.EmptyAppOptions{},
)

// Run randomized simulations
_, simParams, simErr := simulation.SimulateFromSeed(
b,
os.Stdout,
app.BaseApp,
simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
simulationtypes.RandomAccounts,
simapp.SimulationOperations(app, app.AppCodec(), config),
app.ModuleAccountAddrs(),
config,
app.AppCodec(),
)

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

if config.Commit {
simapp.PrintStats(db)
func TestAppStateDeterminism(t *testing.T) {
config := simapp.NewConfigFromFlags()
config.InitialBlockHeight = 1
config.ExportParamsPath = ""
config.OnOperation = false
config.AllInvariants = true
config.NumBlocks = 300
config.BlockSize = 300
config.Commit = true
config.ChainID = helpers.SimAppChainID

numSeeds := 2
numTimesToRunPerSeed := 4
appHashList := make([]json.RawMessage, numTimesToRunPerSeed)

for i := 0; i < numSeeds; i++ {
config.Seed = rand.Int63()

for j := 0; j < numTimesToRunPerSeed; j++ {
var logger log.Logger
if simapp.FlagVerboseValue {
logger = log.TestingLogger()
} else {
logger = log.NewNopLogger()
}

db := dbm.NewMemDB()
app := app.New(
logger,
db,
nil,
true,
map[int64]bool{},
simapp.DefaultNodeHome,
simapp.FlagPeriodValue,
app.MakeEncodingConfig(),
simapp.EmptyAppOptions{},
interBlockCacheOpt(),
)

fmt.Printf(
"running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n",
config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
)

_, _, err := simulation.SimulateFromSeed(
t,
os.Stdout,
app.BaseApp,
simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
simulationtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simapp.SimulationOperations(app, app.AppCodec(), config),
app.ModuleAccountAddrs(),
config,
app.AppCodec(),
)
require.NoError(t, err)

if config.Commit {
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,
)
}
}
}
}

// 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"])
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ require (
github.com/gorilla/mux v1.8.0
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0
github.com/mikluke/co-pilot v0.0.0-20230727024632-ec600865e457
github.com/mikluke/co-pilot v0.0.0-20231002172848-ba00fa031618
github.com/regen-network/cosmos-proto v0.3.1
github.com/spf13/cast v1.5.0
github.com/spf13/cobra v1.6.1
Expand Down Expand Up @@ -159,7 +159,7 @@ require (
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/protobuf v1.30.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
nhooyr.io/websocket v1.8.6 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -675,8 +675,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mikluke/co-pilot v0.0.0-20230727024632-ec600865e457 h1:ng2IZh7o9O6Rpjye3kqnF6ouUv6uQbMgtp0/+9Hsxs0=
github.com/mikluke/co-pilot v0.0.0-20230727024632-ec600865e457/go.mod h1:aKoUiuObP8vhVtv0qX8Rr+im/60IPseqGOdscqYgpBM=
github.com/mikluke/co-pilot v0.0.0-20231002172848-ba00fa031618 h1:nMLk4aJ5dFvsoKLKq2cg0xff2+/P6JmQ8i5Oh/MP5A4=
github.com/mikluke/co-pilot v0.0.0-20231002172848-ba00fa031618/go.mod h1:c5d2OPeqM/ZnXl16TZoNlZQ+jUDG7mNVvhUvcL5pcZA=
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94=
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
Expand Down Expand Up @@ -1442,8 +1442,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
49 changes: 48 additions & 1 deletion x/aviatrix/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ import (
"context"
"encoding/json"
"fmt"
"math/rand"

simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
accountkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
nftkeeper "github.com/cosmos/cosmos-sdk/x/nft/keeper"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/scorum/cosmos-network/x/aviatrix/simulation"
scorumkeeper "github.com/scorum/cosmos-network/x/scorum/keeper"
"github.com/spf13/cobra"

abci "github.com/tendermint/tendermint/abci/types"
Expand Down Expand Up @@ -90,16 +97,28 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command {
type AppModule struct {
AppModuleBasic

keeper keeper.Keeper
keeper keeper.Keeper
scorumKeeper scorumkeeper.Keeper
nftKeeper nftkeeper.Keeper
accountKeeper accountkeeper.AccountKeeper
bankKeeper bankkeeper.Keeper
}

func NewAppModule(
cdc codec.Codec,
keeper keeper.Keeper,
scorumKeeper scorumkeeper.Keeper,
nftKeeper nftkeeper.Keeper,
accountKeeper accountkeeper.AccountKeeper,
bankKeeper bankkeeper.Keeper,
) AppModule {
return AppModule{
AppModuleBasic: NewAppModuleBasic(cdc),
keeper: keeper,
scorumKeeper: scorumKeeper,
nftKeeper: nftKeeper,
accountKeeper: accountKeeper,
bankKeeper: bankKeeper,
}
}

Expand Down Expand Up @@ -150,3 +169,31 @@ func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}
func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{}
}

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

// ProposalContents returns all the distribution content functions used to
// simulate governance proposals.
func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent {
return simulation.ProposalContents(simState)
}

// RandomizedParams creates randomized distribution param changes for the simulator.
func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
return simulation.ParamChanges(r)
}

// RegisterStoreDecoder registers a decoder for distribution module's types
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
// sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc)
}

// WeightedOperations returns the all the gov module operations with their respective weights.
func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
return simulation.WeightedOperations(
simState, am.scorumKeeper, am.nftKeeper, am.accountKeeper, am.bankKeeper,
)
}
Loading

0 comments on commit 6bf35f8

Please sign in to comment.