From c9836274218303b39272e996d921ca9810d108f7 Mon Sep 17 00:00:00 2001 From: Adu Date: Tue, 5 Jul 2022 03:18:30 +0800 Subject: [PATCH] fix: Simulation is not deterministic due to GenTx (backport #12374) (#12437) --- CHANGELOG.md | 2 + simapp/test_helpers.go | 90 ++++++++++++++++++++++++++++++++++++----- x/genutil/gentx_test.go | 1 + x/simulation/util.go | 2 +- 4 files changed, 85 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0235a2c6139..3727681f471f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * (x/mint) [#12384](https://github.com/cosmos/cosmos-sdk/pull/12384) Ensure `GoalBonded` must be positive when performing `x/mint` parameter validation. +* (simapp) [#12437](https://github.com/cosmos/cosmos-sdk/pull/12437) fix the non-determinstic behavior in simulations caused by `GenTx` and check +empty coins slice before it is used to create `banktype.MsgSend`. ## [v0.45.6](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.45.6) - 2022-06-28 diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 7d3c5131466b..f8bd0c4fc62f 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -3,7 +3,8 @@ package simapp import ( "encoding/json" "fmt" - "os" + "math/rand" + "strconv" "testing" abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" @@ -233,17 +234,88 @@ func NewTestNetworkFixture() network.TestFixture { if err != nil { panic(fmt.Sprintf("failed creating temporary directory: %v", err)) } - defer os.RemoveAll(dir) + if !bytes.Equal(bechres, res) { + return nil, err + } + + return res, nil +} + +// CheckBalance checks the balance of an account. +func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, balances sdk.Coins) { + ctxCheck := app.BaseApp.NewContext(true, tmproto.Header{}) + require.True(t, balances.IsEqual(app.BankKeeper.GetAllBalances(ctxCheck, addr))) +} + +// SignCheckDeliver checks a generated signed transaction and simulates a +// block commitment with the given transaction. A test assertion is made using +// the parameter 'expPass' against the result. A corresponding result is +// returned. +func SignCheckDeliver( + t *testing.T, txCfg client.TxConfig, app *bam.BaseApp, header tmproto.Header, msgs []sdk.Msg, + chainID string, accNums, accSeqs []uint64, expSimPass, expPass bool, priv ...cryptotypes.PrivKey, +) (sdk.GasInfo, *sdk.Result, error) { + + tx, err := helpers.GenTx( + rand.New(rand.NewSource(time.Now().UnixNano())), + txCfg, + msgs, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}, + helpers.DefaultGenTxGas, + chainID, + accNums, + accSeqs, + priv..., + ) + require.NoError(t, err) + txBytes, err := txCfg.TxEncoder()(tx) + require.Nil(t, err) app := NewSimApp(log.NewNopLogger(), coretesting.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(dir)) - appCtr := func(val network.ValidatorI) servertypes.Application { - return NewSimApp( - val.GetLogger(), coretesting.NewMemDB(), nil, true, - simtestutil.NewAppOptionsWithFlagHome(client.GetConfigFromViper(val.GetViper()).RootDir), - bam.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)), - bam.SetMinGasPrices(val.GetAppConfig().MinGasPrices), - bam.SetChainID(val.GetViper().GetString(flags.FlagChainID)), + if expSimPass { + require.NoError(t, err) + require.NotNil(t, res) + } else { + require.Error(t, err) + require.Nil(t, res) + } + + // Simulate a sending a transaction and committing a block + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + gInfo, res, err := app.Deliver(txCfg.TxEncoder(), tx) + + if expPass { + require.NoError(t, err) + require.NotNil(t, res) + } else { + require.Error(t, err) + require.Nil(t, res) + } + + app.EndBlock(abci.RequestEndBlock{}) + app.Commit() + + return gInfo, res, err +} + +// GenSequenceOfTxs generates a set of signed transactions of messages, such +// that they differ only by having the sequence numbers incremented between +// every transaction. +func GenSequenceOfTxs(txGen client.TxConfig, msgs []sdk.Msg, accNums []uint64, initSeqNums []uint64, numToGenerate int, priv ...cryptotypes.PrivKey) ([]sdk.Tx, error) { + txs := make([]sdk.Tx, numToGenerate) + var err error + for i := 0; i < numToGenerate; i++ { + txs[i], err = helpers.GenTx( + rand.New(rand.NewSource(time.Now().UnixNano())), + txGen, + msgs, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}, + helpers.DefaultGenTxGas, + "", + accNums, + initSeqNums, + priv..., ) } diff --git a/x/genutil/gentx_test.go b/x/genutil/gentx_test.go index a38e83551a26..41744df9a891 100644 --- a/x/genutil/gentx_test.go +++ b/x/genutil/gentx_test.go @@ -273,6 +273,7 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() { msg := banktypes.NewMsgSend(addr1, addr2, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)}) tx, err := helpers.GenTx( + rand.New(rand.NewSource(time.Now().UnixNano())), suite.encodingConfig.TxConfig, []sdk.Msg{msg}, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)}, diff --git a/x/simulation/util.go b/x/simulation/util.go index c2a3cdcd7bad..d21f8d8ee206 100644 --- a/x/simulation/util.go +++ b/x/simulation/util.go @@ -99,7 +99,7 @@ func GenAndDeliverTxWithRandFees(txCtx OperationInput) (simtypes.OperationMsg, [ // GenAndDeliverTx generates a transactions and delivers it. func GenAndDeliverTx(txCtx OperationInput, fees sdk.Coins) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { account := txCtx.AccountKeeper.GetAccount(txCtx.Context, txCtx.SimAccount.Address) - tx, err := simtestutil.GenSignedMockTx( + tx, err := helpers.GenTx( txCtx.R, txCtx.TxGen, []sdk.Msg{txCtx.Msg},