From 126b8b299aedd72d8f8b4050b23708e78c07f8b9 Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 27 Sep 2023 20:45:33 +0800 Subject: [PATCH 1/8] fix(simulation): fix account randomly generated by AppStateFromGenesisFileFn does not have ConsKey causing SimulateMsgCreateValidator fail --- testutil/sims/state_helpers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testutil/sims/state_helpers.go b/testutil/sims/state_helpers.go index 55b7a5b06556..cf337dd575c5 100644 --- a/testutil/sims/state_helpers.go +++ b/testutil/sims/state_helpers.go @@ -3,6 +3,7 @@ package sims import ( "encoding/json" "fmt" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "io" "math/rand" "os" @@ -288,7 +289,7 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile str } // create simulator accounts - simAcc := simtypes.Account{PrivKey: privKey, PubKey: privKey.PubKey(), Address: a.GetAddress()} + simAcc := simtypes.Account{PrivKey: privKey, PubKey: privKey.PubKey(), Address: a.GetAddress(), ConsKey: ed25519.GenPrivKeyFromSecret(privkeySeed)} newAccs[i] = simAcc } From f9f3f76e3e69e3f0f079a0431ca14f943c139807 Mon Sep 17 00:00:00 2001 From: luke Date: Wed, 27 Sep 2023 21:32:59 +0800 Subject: [PATCH 2/8] fix(simulation): fix the problem of operating group such as SimulateMsgCreateGroupPolicy when the group does not exist in the chain during simulation test --- x/group/simulation/operations.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/x/group/simulation/operations.go b/x/group/simulation/operations.go index 978ede478797..42d3ac4a64c7 100644 --- a/x/group/simulation/operations.go +++ b/x/group/simulation/operations.go @@ -1229,8 +1229,9 @@ func randomGroup(r *rand.Rand, k keeper.Keeper, ak group.AccountKeeper, switch { case groupID > initialGroupID: - // select a random ID between [initialGroupID, groupID] - groupID = uint64(simtypes.RandIntBetween(r, int(initialGroupID), int(groupID))) + // select a random ID between (initialGroupID, groupID] + // if there is at least one group information, then the groupID at this time must be greater than or equal to 1 + groupID = uint64(simtypes.RandIntBetween(r, int(initialGroupID+1), int(groupID+1))) default: // This is called on the first call to this function @@ -1238,6 +1239,11 @@ func randomGroup(r *rand.Rand, k keeper.Keeper, ak group.AccountKeeper, initialGroupID = groupID } + // when groupID is 0, it proves that SimulateMsgCreateGroup has never been called. that is, no group exists in the chain + if groupID == 0 { + return nil, simtypes.Account{}, nil, nil + } + res, err := k.GroupInfo(ctx, &group.QueryGroupInfoRequest{GroupId: groupID}) if err != nil { return nil, simtypes.Account{}, nil, err From 6aaaa0a80c841542f5ec8b0a6a8329ee9f2d463a Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 28 Sep 2023 00:10:56 +0800 Subject: [PATCH 3/8] fix(simulation): skip sigverify check when run simulation test --- CHANGELOG.md | 1 + Makefile | 8 ++++---- baseapp/baseapp.go | 25 +++++++++++++++++-------- baseapp/test_helpers.go | 4 ++-- types/context.go | 10 ++++++++++ x/auth/ante/sigverify.go | 4 ++-- 6 files changed, 36 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a805200b890..fa12324ae0fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * (x/gov) [#17873](https://github.com/cosmos/cosmos-sdk/pull/17873) Fail any inactive and active proposals whose messages cannot be decoded. +* (simulation) [#17910](https://github.com/cosmos/cosmos-sdk/pull/17910) Fix all problems with executing command `make test-sim-custom-genesis-fast` for simulation test. ### API Breaking Changes diff --git a/Makefile b/Makefile index 6fe028d1a7be..6c4f658e684f 100644 --- a/Makefile +++ b/Makefile @@ -270,8 +270,8 @@ test-sim-nondeterminism-streaming: test-sim-custom-genesis-fast: @echo "Running custom genesis simulation..." - @echo "By default, ${HOME}/.gaiad/config/genesis.json will be used." - @cd ${CURRENT_DIR}/simapp && go test -mod=readonly -run TestFullAppSimulation -Genesis=${HOME}/.gaiad/config/genesis.json \ + @echo "By default, ${HOME}/.simapp/config/genesis.json will be used." + @cd ${CURRENT_DIR}/simapp && go test -mod=readonly -run TestFullAppSimulation -Genesis=${HOME}/.simapp/config/genesis.json \ -Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h test-sim-import-export: runsim @@ -284,8 +284,8 @@ test-sim-after-import: runsim test-sim-custom-genesis-multi-seed: runsim @echo "Running multi-seed custom genesis simulation..." - @echo "By default, ${HOME}/.gaiad/config/genesis.json will be used." - @cd ${CURRENT_DIR}/simapp && $(BINDIR)/runsim -Genesis=${HOME}/.gaiad/config/genesis.json -SimAppPkg=. -ExitOnFail 400 5 TestFullAppSimulation + @echo "By default, ${HOME}/.simapp/config/genesis.json will be used." + @cd ${CURRENT_DIR}/simapp && $(BINDIR)/runsim -Genesis=${HOME}/.simapp/config/genesis.json -SimAppPkg=. -ExitOnFail 400 5 TestFullAppSimulation test-sim-multi-seed-long: runsim @echo "Running long multi-seed application simulation. This may take awhile!" diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index d890d8022044..bdb0ea526930 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -45,13 +45,14 @@ type ( ) const ( - execModeCheck execMode = iota // Check a transaction - execModeReCheck // Recheck a (pending) transaction after a commit - execModeSimulate // Simulate a transaction - execModePrepareProposal // Prepare a block proposal - execModeProcessProposal // Process a block proposal - execModeVoteExtension // Extend or verify a pre-commit vote - execModeFinalize // Finalize a block proposal + execModeCheck execMode = iota // Check a transaction + execModeReCheck // Recheck a (pending) transaction after a commit + execModeSimulate // Simulate a transaction + execModePrepareProposal // Prepare a block proposal + execModeProcessProposal // Process a block proposal + execModeVoteExtension // Extend or verify a pre-commit vote + execModeFinalize // Finalize a block proposal + execModeSimulationFinalize // Finalize a block proposal when run simulation, for example TestFullAppSimulation ) var _ servertypes.ABCI = (*BaseApp)(nil) @@ -610,7 +611,7 @@ func validateBasicTxMsgs(msgs []sdk.Msg) error { func (app *BaseApp) getState(mode execMode) *state { switch mode { - case execModeFinalize: + case execModeFinalize, execModeSimulationFinalize: return app.finalizeBlockState case execModePrepareProposal: @@ -642,6 +643,8 @@ func (app *BaseApp) getContextForTx(mode execMode, txBytes []byte) sdk.Context { WithTxBytes(txBytes) // WithVoteInfos(app.voteInfos) // TODO: identify if this is needed + ctx = ctx.WithIsSigverifyTx(mode != execModeSimulationFinalize) + ctx = ctx.WithConsensusParams(app.GetConsensusParams(ctx)) if mode == execModeReCheck { @@ -797,6 +800,12 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res var gasWanted uint64 ctx := app.getContextForTx(mode, txBytes) + // after we set the sigverifyTx field in ctx in the function app.getContextForTx(mode, txBytes) + // we restore the mode value to facilitate logical judgment. + if mode == execModeSimulationFinalize { + mode = execModeFinalize + } + ms := ctx.MultiStore() // only run the tx if there is block gas remaining diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index cd3dd0baec0f..3d01ac242108 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -35,7 +35,7 @@ func (app *BaseApp) SimDeliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, if err != nil { return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.runTx(execModeFinalize, bz) + gasInfo, result, _, err := app.runTx(execModeSimulationFinalize, bz) return gasInfo, result, err } @@ -46,7 +46,7 @@ func (app *BaseApp) SimTxFinalizeBlock(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk. return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.runTx(execModeFinalize, bz) + gasInfo, result, _, err := app.runTx(execModeSimulationFinalize, bz) return gasInfo, result, err } diff --git a/types/context.go b/types/context.go index 79181d065c8c..192163d5f2a6 100644 --- a/types/context.go +++ b/types/context.go @@ -50,6 +50,7 @@ type Context struct { blockGasMeter storetypes.GasMeter checkTx bool recheckTx bool // if recheckTx == true, then checkTx must also be true + sigverifyTx bool // when run simulation, because the private key corresponding to the account in the genesis.json randomly generated, we must skip the sigverify. execMode ExecMode minGasPrice DecCoins consParams cmtproto.ConsensusParams @@ -78,6 +79,7 @@ func (c Context) GasMeter() storetypes.GasMeter { return c.gasMe func (c Context) BlockGasMeter() storetypes.GasMeter { return c.blockGasMeter } func (c Context) IsCheckTx() bool { return c.checkTx } func (c Context) IsReCheckTx() bool { return c.recheckTx } +func (c Context) IsSigverifyTx() bool { return c.sigverifyTx } func (c Context) ExecMode() ExecMode { return c.execMode } func (c Context) MinGasPrices() DecCoins { return c.minGasPrice } func (c Context) EventManager() EventManagerI { return c.eventManager } @@ -127,6 +129,7 @@ func NewContext(ms storetypes.MultiStore, isCheckTx bool, logger log.Logger) Con header: h, chainID: h.ChainID, checkTx: isCheckTx, + sigverifyTx: true, logger: logger, gasMeter: storetypes.NewInfiniteGasMeter(), minGasPrice: DecCoins{}, @@ -254,6 +257,13 @@ func (c Context) WithIsReCheckTx(isRecheckTx bool) Context { return c } +// WithIsSigverifyTx called with true will sigverify in auth module +// If the transaction is executed in execModeSimulationFinalize mode, the sigverify check will be skipped. +func (c Context) WithIsSigverifyTx(isSigverifyTx bool) Context { + c.sigverifyTx = isSigverifyTx + return c +} + // WithExecMode returns a Context with an updated ExecMode. func (c Context) WithExecMode(m ExecMode) Context { c.execMode = m diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index 9f7c18d57cb2..c588f2b78276 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -90,7 +90,7 @@ func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b pk = simSecp256k1Pubkey } // Only make check if simulate=false - if !simulate && !bytes.Equal(pk.Address(), signers[i]) { + if !simulate && !bytes.Equal(pk.Address(), signers[i]) && ctx.IsSigverifyTx() { return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidPubKey, "pubKey does not match signer address %s with signer index: %d", signerStrs[i], i) } @@ -302,7 +302,7 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul } // no need to verify signatures on recheck tx - if !simulate && !ctx.IsReCheckTx() { + if !simulate && !ctx.IsReCheckTx() && ctx.IsSigverifyTx() { anyPk, _ := codectypes.NewAnyWithValue(pubKey) signerData := txsigning.SignerData{ From 0b0b283226b2da8bd6216532743902de5354fd06 Mon Sep 17 00:00:00 2001 From: luke Date: Thu, 28 Sep 2023 00:45:03 +0800 Subject: [PATCH 4/8] chore: update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa12324ae0fd..585e07d1fb9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,7 +59,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * (x/gov) [#17873](https://github.com/cosmos/cosmos-sdk/pull/17873) Fail any inactive and active proposals whose messages cannot be decoded. -* (simulation) [#17910](https://github.com/cosmos/cosmos-sdk/pull/17910) Fix all problems with executing command `make test-sim-custom-genesis-fast` for simulation test. +* (simulation) [#17911](https://github.com/cosmos/cosmos-sdk/pull/17911) Fix all problems with executing command `make test-sim-custom-genesis-fast` for simulation test. ### API Breaking Changes From 8996f6bb18a2a2bcaf7990381e75abb4c172a9a0 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 9 Oct 2023 13:40:21 +0800 Subject: [PATCH 5/8] fix(simulation): add an SigverifyTx flag in the simulation test whether to sigverify check for transaction --- Makefile | 4 ++-- baseapp/baseapp.go | 27 +++++++++++---------------- baseapp/options.go | 5 +++++ baseapp/test_helpers.go | 8 ++++---- simapp/sim_test.go | 12 ++++++++++++ testutil/sims/state_helpers.go | 20 +++++++++++++------- types/context.go | 1 - x/simulation/client/cli/flags.go | 2 ++ x/simulation/simulate.go | 6 ++++-- 9 files changed, 53 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index 6c4f658e684f..cbb173de88f3 100644 --- a/Makefile +++ b/Makefile @@ -272,7 +272,7 @@ test-sim-custom-genesis-fast: @echo "Running custom genesis simulation..." @echo "By default, ${HOME}/.simapp/config/genesis.json will be used." @cd ${CURRENT_DIR}/simapp && go test -mod=readonly -run TestFullAppSimulation -Genesis=${HOME}/.simapp/config/genesis.json \ - -Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h + -Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -SigverifyTx=false -v -timeout 24h test-sim-import-export: runsim @echo "Running application import/export simulation. This may take several minutes..." @@ -285,7 +285,7 @@ test-sim-after-import: runsim test-sim-custom-genesis-multi-seed: runsim @echo "Running multi-seed custom genesis simulation..." @echo "By default, ${HOME}/.simapp/config/genesis.json will be used." - @cd ${CURRENT_DIR}/simapp && $(BINDIR)/runsim -Genesis=${HOME}/.simapp/config/genesis.json -SimAppPkg=. -ExitOnFail 400 5 TestFullAppSimulation + @cd ${CURRENT_DIR}/simapp && $(BINDIR)/runsim -Genesis=${HOME}/.simapp/config/genesis.json -SigverifyTx=false -SimAppPkg=. -ExitOnFail 400 5 TestFullAppSimulation test-sim-multi-seed-long: runsim @echo "Running long multi-seed application simulation. This may take awhile!" diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index bdb0ea526930..b92e797ceb51 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -45,14 +45,13 @@ type ( ) const ( - execModeCheck execMode = iota // Check a transaction - execModeReCheck // Recheck a (pending) transaction after a commit - execModeSimulate // Simulate a transaction - execModePrepareProposal // Prepare a block proposal - execModeProcessProposal // Process a block proposal - execModeVoteExtension // Extend or verify a pre-commit vote - execModeFinalize // Finalize a block proposal - execModeSimulationFinalize // Finalize a block proposal when run simulation, for example TestFullAppSimulation + execModeCheck execMode = iota // Check a transaction + execModeReCheck // Recheck a (pending) transaction after a commit + execModeSimulate // Simulate a transaction + execModePrepareProposal // Prepare a block proposal + execModeProcessProposal // Process a block proposal + execModeVoteExtension // Extend or verify a pre-commit vote + execModeFinalize // Finalize a block proposal ) var _ servertypes.ABCI = (*BaseApp)(nil) @@ -90,6 +89,7 @@ type BaseApp struct { addrPeerFilter sdk.PeerFilter // filter peers by address and port idPeerFilter sdk.PeerFilter // filter peers by node ID fauxMerkleMode bool // if true, IAVL MountStores uses MountStoresDB for simulation speed. + sigverifyTx bool // whether to sigverify check for transaction // manages snapshots, i.e. dumps of app state at certain intervals snapshotManager *snapshots.Manager @@ -199,6 +199,7 @@ func NewBaseApp( msgServiceRouter: NewMsgServiceRouter(), txDecoder: txDecoder, fauxMerkleMode: false, + sigverifyTx: true, queryGasLimit: math.MaxUint64, } @@ -611,7 +612,7 @@ func validateBasicTxMsgs(msgs []sdk.Msg) error { func (app *BaseApp) getState(mode execMode) *state { switch mode { - case execModeFinalize, execModeSimulationFinalize: + case execModeFinalize: return app.finalizeBlockState case execModePrepareProposal: @@ -643,7 +644,7 @@ func (app *BaseApp) getContextForTx(mode execMode, txBytes []byte) sdk.Context { WithTxBytes(txBytes) // WithVoteInfos(app.voteInfos) // TODO: identify if this is needed - ctx = ctx.WithIsSigverifyTx(mode != execModeSimulationFinalize) + ctx = ctx.WithIsSigverifyTx(app.sigverifyTx) ctx = ctx.WithConsensusParams(app.GetConsensusParams(ctx)) @@ -800,12 +801,6 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res var gasWanted uint64 ctx := app.getContextForTx(mode, txBytes) - // after we set the sigverifyTx field in ctx in the function app.getContextForTx(mode, txBytes) - // we restore the mode value to facilitate logical judgment. - if mode == execModeSimulationFinalize { - mode = execModeFinalize - } - ms := ctx.MultiStore() // only run the tx if there is block gas remaining diff --git a/baseapp/options.go b/baseapp/options.go index 68d2704b3610..18fbf4a062c7 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -264,6 +264,11 @@ func (app *BaseApp) SetFauxMerkleMode() { app.fauxMerkleMode = true } +// SetNotSigverify during simulation testing, transaction signature verification needs to be ignored. +func (app *BaseApp) SetNotSigverifyTx() { + app.sigverifyTx = false +} + // SetCommitMultiStoreTracer sets the store tracer on the BaseApp's underlying // CommitMultiStore. func (app *BaseApp) SetCommitMultiStoreTracer(w io.Writer) { diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index 3d01ac242108..bf2caed20a8e 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -1,9 +1,8 @@ package baseapp import ( - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - errorsmod "cosmossdk.io/errors" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -35,7 +34,8 @@ func (app *BaseApp) SimDeliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, if err != nil { return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.runTx(execModeSimulationFinalize, bz) + + gasInfo, result, _, err := app.runTx(execModeFinalize, bz) return gasInfo, result, err } @@ -46,7 +46,7 @@ func (app *BaseApp) SimTxFinalizeBlock(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk. return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.runTx(execModeSimulationFinalize, bz) + gasInfo, result, _, err := app.runTx(execModeFinalize, bz) return gasInfo, result, err } diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 00dba9ec7b8c..1faffe9942ea 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -76,6 +76,9 @@ func TestFullAppSimulation(t *testing.T) { appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue app := NewSimApp(logger, db, nil, true, appOptions, fauxMerkleModeOpt, baseapp.SetChainID(SimAppChainID)) + if !simcli.FlagSigverifyTxValue { + app.SetNotSigverifyTx() + } require.Equal(t, "SimApp", app.Name()) // run randomized simulation @@ -121,6 +124,9 @@ func TestAppImportExport(t *testing.T) { appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue app := NewSimApp(logger, db, nil, true, appOptions, fauxMerkleModeOpt, baseapp.SetChainID(SimAppChainID)) + if !simcli.FlagSigverifyTxValue { + app.SetNotSigverifyTx() + } require.Equal(t, "SimApp", app.Name()) // Run randomized simulation @@ -240,6 +246,9 @@ func TestAppSimulationAfterImport(t *testing.T) { appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue app := NewSimApp(logger, db, nil, true, appOptions, fauxMerkleModeOpt, baseapp.SetChainID(SimAppChainID)) + if !simcli.FlagSigverifyTxValue { + app.SetNotSigverifyTx() + } require.Equal(t, "SimApp", app.Name()) // Run randomized simulation @@ -362,6 +371,9 @@ func TestAppStateDeterminism(t *testing.T) { db := dbm.NewMemDB() app := NewSimApp(logger, db, nil, true, appOptions, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) + if !simcli.FlagSigverifyTxValue { + app.SetNotSigverifyTx() + } fmt.Printf( "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n", diff --git a/testutil/sims/state_helpers.go b/testutil/sims/state_helpers.go index cf337dd575c5..d080d88992ab 100644 --- a/testutil/sims/state_helpers.go +++ b/testutil/sims/state_helpers.go @@ -1,12 +1,14 @@ package sims import ( + "bufio" "encoding/json" "fmt" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "io" "math/rand" "os" + "path/filepath" "time" "github.com/cosmos/gogoproto/proto" @@ -251,19 +253,23 @@ 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) (genutiltypes.AppGenesis, []simtypes.Account, error) { - bytes, err := os.ReadFile(genesisFile) + file, err := os.Open(filepath.Clean(genesisFile)) if err != nil { panic(err) } - var genesis genutiltypes.AppGenesis - if err = json.Unmarshal(bytes, &genesis); err != nil { - return genesis, nil, err + genesis, err := genutiltypes.AppGenesisFromReader(bufio.NewReader(file)) + if err != nil { + return *genesis, nil, err + } + + if err := file.Close(); err != nil { + return *genesis, nil, err } var appState map[string]json.RawMessage if err = json.Unmarshal(genesis.AppState, &appState); err != nil { - return genesis, nil, err + return *genesis, nil, err } var authGenesis authtypes.GenesisState @@ -285,7 +291,7 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile str a, ok := acc.GetCachedValue().(sdk.AccountI) if !ok { - return genesis, nil, fmt.Errorf("expected account") + return *genesis, nil, fmt.Errorf("expected account") } // create simulator accounts @@ -293,5 +299,5 @@ func AppStateFromGenesisFileFn(r io.Reader, cdc codec.JSONCodec, genesisFile str newAccs[i] = simAcc } - return genesis, newAccs, nil + return *genesis, newAccs, nil } diff --git a/types/context.go b/types/context.go index 192163d5f2a6..e323aa7534bb 100644 --- a/types/context.go +++ b/types/context.go @@ -258,7 +258,6 @@ func (c Context) WithIsReCheckTx(isRecheckTx bool) Context { } // WithIsSigverifyTx called with true will sigverify in auth module -// If the transaction is executed in execModeSimulationFinalize mode, the sigverify check will be skipped. func (c Context) WithIsSigverifyTx(isSigverifyTx bool) Context { c.sigverifyTx = isSigverifyTx return c diff --git a/x/simulation/client/cli/flags.go b/x/simulation/client/cli/flags.go index 43f0e4c52465..c157bdb8e805 100644 --- a/x/simulation/client/cli/flags.go +++ b/x/simulation/client/cli/flags.go @@ -30,6 +30,7 @@ var ( FlagVerboseValue bool FlagPeriodValue uint FlagGenesisTimeValue int64 + FlagSigverifyTxValue bool ) // GetSimulatorFlags gets the values of all the available simulation flags @@ -56,6 +57,7 @@ func GetSimulatorFlags() { flag.BoolVar(&FlagVerboseValue, "Verbose", false, "verbose log output") flag.UintVar(&FlagPeriodValue, "Period", 0, "run slow invariants only once every period assertions") flag.Int64Var(&FlagGenesisTimeValue, "GenesisTime", 0, "override genesis UNIX time instead of using a random UNIX time") + flag.BoolVar(&FlagSigverifyTxValue, "SigverifyTx", true, "whether to sigverify check for transaction ") } // NewConfigFromFlags creates a simulation from the retrieved values of the flags. diff --git a/x/simulation/simulate.go b/x/simulation/simulate.go index 806b5d3a40b7..021e66a47cc9 100644 --- a/x/simulation/simulate.go +++ b/x/simulation/simulate.go @@ -84,8 +84,10 @@ func SimulateFromSeed( // Second variable to keep pending validator set (delayed one block since // TM 0.24) Initially this is the same as the initial validator set validators, blockTime, accs, chainID := initChain(r, params, accs, app, appStateFn, config, cdc) - if len(accs) == 0 { - return true, params, fmt.Errorf("must have greater than zero genesis accounts") + // At least 2 accounts must be added here, otherwise when executing SimulateMsgSend + // two accounts will be selected to meet the conditions from != to and it will fall into an infinite loop. + if len(accs) <= 1 { + return true, params, fmt.Errorf("At least two genesis accounts are required") } config.ChainID = chainID From bc7a998b1bc5bcf43b760ee66b2238782b1fbc5f Mon Sep 17 00:00:00 2001 From: Luke Date: Fri, 13 Oct 2023 17:30:11 +0800 Subject: [PATCH 6/8] chore: fix commit error strings should not be capitalized --- x/simulation/simulate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/simulation/simulate.go b/x/simulation/simulate.go index 021e66a47cc9..779cad91c1b9 100644 --- a/x/simulation/simulate.go +++ b/x/simulation/simulate.go @@ -87,7 +87,7 @@ func SimulateFromSeed( // At least 2 accounts must be added here, otherwise when executing SimulateMsgSend // two accounts will be selected to meet the conditions from != to and it will fall into an infinite loop. if len(accs) <= 1 { - return true, params, fmt.Errorf("At least two genesis accounts are required") + return true, params, fmt.Errorf("at least two genesis accounts are required") } config.ChainID = chainID From 25d1c20d831279d063c575921b3a0ff0723c43d1 Mon Sep 17 00:00:00 2001 From: Luke Date: Fri, 13 Oct 2023 18:09:11 +0800 Subject: [PATCH 7/8] chore: run make lint-fix and update commit --- baseapp/baseapp.go | 2 +- baseapp/test_helpers.go | 3 ++- testutil/sims/state_helpers.go | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index b92e797ceb51..9e7680a3ad1d 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -89,7 +89,7 @@ type BaseApp struct { addrPeerFilter sdk.PeerFilter // filter peers by address and port idPeerFilter sdk.PeerFilter // filter peers by node ID fauxMerkleMode bool // if true, IAVL MountStores uses MountStoresDB for simulation speed. - sigverifyTx bool // whether to sigverify check for transaction + sigverifyTx bool // in the simulation test, since the account does not have a private key, we have to ignore the tx sigverify. // manages snapshots, i.e. dumps of app state at certain intervals snapshotManager *snapshots.Manager diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index bf2caed20a8e..4adc20535cf9 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -1,9 +1,10 @@ package baseapp import ( - errorsmod "cosmossdk.io/errors" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) diff --git a/testutil/sims/state_helpers.go b/testutil/sims/state_helpers.go index d080d88992ab..af7da68e753c 100644 --- a/testutil/sims/state_helpers.go +++ b/testutil/sims/state_helpers.go @@ -4,18 +4,20 @@ import ( "bufio" "encoding/json" "fmt" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "io" "math/rand" "os" "path/filepath" "time" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/gogoproto/proto" "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" From 958e45bde454d67cac9257f9c4276f15d23afae8 Mon Sep 17 00:00:00 2001 From: Luke Date: Fri, 13 Oct 2023 20:10:01 +0800 Subject: [PATCH 8/8] fix(simulation): add a test in sigverify_test to harden --- testutil/sims/state_helpers.go | 2 -- x/auth/ante/sigverify_test.go | 19 +++++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/testutil/sims/state_helpers.go b/testutil/sims/state_helpers.go index af7da68e753c..a5c4eb60b792 100644 --- a/testutil/sims/state_helpers.go +++ b/testutil/sims/state_helpers.go @@ -10,8 +10,6 @@ import ( "path/filepath" "time" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - "github.com/cosmos/gogoproto/proto" "cosmossdk.io/math" diff --git a/x/auth/ante/sigverify_test.go b/x/auth/ante/sigverify_test.go index 45049aaedf06..ee19482d8c64 100644 --- a/x/auth/ante/sigverify_test.go +++ b/x/auth/ante/sigverify_test.go @@ -190,23 +190,26 @@ func TestSigVerification(t *testing.T) { accSeqs []uint64 invalidSigs bool // used for testing sigverify on RecheckTx recheck bool + sigverify bool shouldErr bool } validSigs := false testCases := []testCase{ - {"no signers", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, validSigs, false, true}, - {"not enough signers", []cryptotypes.PrivKey{priv1, priv2}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber()}, []uint64{0, 0}, validSigs, false, true}, - {"wrong order signers", []cryptotypes.PrivKey{priv3, priv2, priv1}, []uint64{accs[2].GetAccountNumber(), accs[1].GetAccountNumber(), accs[0].GetAccountNumber()}, []uint64{0, 0, 0}, validSigs, false, true}, - {"wrong accnums", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{7, 8, 9}, []uint64{0, 0, 0}, validSigs, false, true}, - {"wrong sequences", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber(), accs[2].GetAccountNumber()}, []uint64{3, 4, 5}, validSigs, false, true}, - {"valid tx", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber(), accs[2].GetAccountNumber()}, []uint64{0, 0, 0}, validSigs, false, false}, - {"no err on recheck", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 0, 0}, []uint64{0, 0, 0}, !validSigs, true, false}, + {"no signers", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, validSigs, false, true, true}, + {"not enough signers", []cryptotypes.PrivKey{priv1, priv2}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber()}, []uint64{0, 0}, validSigs, false, true, true}, + {"wrong order signers", []cryptotypes.PrivKey{priv3, priv2, priv1}, []uint64{accs[2].GetAccountNumber(), accs[1].GetAccountNumber(), accs[0].GetAccountNumber()}, []uint64{0, 0, 0}, validSigs, false, true, true}, + {"wrong accnums", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{7, 8, 9}, []uint64{0, 0, 0}, validSigs, false, true, true}, + {"wrong sequences", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber(), accs[2].GetAccountNumber()}, []uint64{3, 4, 5}, validSigs, false, true, true}, + {"valid tx", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber(), accs[2].GetAccountNumber()}, []uint64{0, 0, 0}, validSigs, false, true, false}, + {"sigverify tx with wrong order signers", []cryptotypes.PrivKey{priv3, priv2, priv1}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber(), accs[2].GetAccountNumber()}, []uint64{0, 0, 0}, validSigs, false, true, true}, + {"skip sigverify tx with wrong order signers", []cryptotypes.PrivKey{priv3, priv2, priv1}, []uint64{accs[0].GetAccountNumber(), accs[1].GetAccountNumber(), accs[2].GetAccountNumber()}, []uint64{0, 0, 0}, validSigs, false, false, false}, + {"no err on recheck", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 0, 0}, []uint64{0, 0, 0}, !validSigs, true, true, false}, } for i, tc := range testCases { for _, signMode := range enabledSignModes { t.Run(fmt.Sprintf("%s with %s", tc.name, signMode), func(t *testing.T) { - suite.ctx = suite.ctx.WithIsReCheckTx(tc.recheck) + suite.ctx = suite.ctx.WithIsReCheckTx(tc.recheck).WithIsSigverifyTx(tc.sigverify) suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() // Create new txBuilder for each test require.NoError(t, suite.txBuilder.SetMsgs(msgs...))