github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/testing/simapp/sim_test.go (about)

     1  package simapp
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"math/rand"
     7  	"os"
     8  	"testing"
     9  
    10  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    11  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
    12  	dbm "github.com/fibonacci-chain/fbc/libs/tm-db"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/baseapp"
    16  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store"
    17  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    18  	authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types"
    19  	banktypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/bank"
    20  	capabilitytypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/capability/types"
    21  	distrtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/distribution/types"
    22  	evidencetypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/evidence"
    23  	govtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/gov/types"
    24  	minttypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/mint"
    25  	paramtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/params/types"
    26  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/simulation"
    27  	slashingtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/slashing"
    28  	stakingtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/staking/types"
    29  	ibctransfertypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/apps/transfer/types"
    30  	ibchost "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/24-host"
    31  	"github.com/fibonacci-chain/fbc/libs/ibc-go/testing/simapp/helpers"
    32  )
    33  
    34  // Get flags every time the simulator is run
    35  func init() {
    36  	GetSimulatorFlags()
    37  }
    38  
    39  type StoreKeysPrefixes struct {
    40  	A        sdk.StoreKey
    41  	B        sdk.StoreKey
    42  	Prefixes [][]byte
    43  }
    44  
    45  // fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
    46  // an IAVLStore for faster simulation speed.
    47  func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
    48  	bapp.SetFauxMerkleMode()
    49  }
    50  
    51  // interBlockCacheOpt returns a BaseApp option function that sets the persistent
    52  // inter-block write-through cache.
    53  func interBlockCacheOpt() func(*baseapp.BaseApp) {
    54  	return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager())
    55  }
    56  
    57  func TestFullAppSimulation(t *testing.T) {
    58  	config, db, dir, logger, skip, err := SetupSimulation("leveldb-app-sim", "Simulation")
    59  	if skip {
    60  		t.Skip("skipping application simulation")
    61  	}
    62  	require.NoError(t, err, "simulation setup failed")
    63  
    64  	defer func() {
    65  		db.Close()
    66  		require.NoError(t, os.RemoveAll(dir))
    67  	}()
    68  
    69  	app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt)
    70  	require.Equal(t, "SimApp", app.Name())
    71  
    72  	// run randomized simulation
    73  	_, simParams, simErr := simulation.SimulateFromSeed(
    74  		t,
    75  		os.Stdout,
    76  		app.BaseApp,
    77  		AppStateFn(*app.AppCodec(), app.SimulationManager()),
    78  		//		simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
    79  		SimulationOperations(app, *app.AppCodec().GetCdc(), config),
    80  		app.ModuleAccountAddrs(),
    81  		config,
    82  	)
    83  
    84  	// export state and simParams before the simulation error is checked
    85  	err = CheckExportSimulation(app, config, simParams)
    86  	require.NoError(t, err)
    87  	require.NoError(t, simErr)
    88  
    89  	if config.Commit {
    90  		PrintStats(db)
    91  	}
    92  }
    93  
    94  func TestAppImportExport(t *testing.T) {
    95  	config, db, dir, logger, skip, err := SetupSimulation("leveldb-app-sim", "Simulation")
    96  	if skip {
    97  		t.Skip("skipping application import/export simulation")
    98  	}
    99  	require.NoError(t, err, "simulation setup failed")
   100  
   101  	defer func() {
   102  		db.Close()
   103  		require.NoError(t, os.RemoveAll(dir))
   104  	}()
   105  
   106  	app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt)
   107  	require.Equal(t, "SimApp", app.Name())
   108  
   109  	// Run randomized simulation
   110  	_, simParams, simErr := simulation.SimulateFromSeed(
   111  		t,
   112  		os.Stdout,
   113  		app.BaseApp,
   114  		AppStateFn(*app.AppCodec(), app.SimulationManager()),
   115  		//		simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
   116  		SimulationOperations(app, *app.AppCodec().GetCdc(), config),
   117  		app.ModuleAccountAddrs(),
   118  		config,
   119  	)
   120  
   121  	// export state and simParams before the simulation error is checked
   122  	err = CheckExportSimulation(app, config, simParams)
   123  	require.NoError(t, err)
   124  	require.NoError(t, simErr)
   125  
   126  	if config.Commit {
   127  		PrintStats(db)
   128  	}
   129  
   130  	fmt.Printf("exporting genesis...\n")
   131  
   132  	exported, _, err := app.ExportAppStateAndValidators(false, []string{})
   133  	require.NoError(t, err)
   134  
   135  	fmt.Printf("importing genesis...\n")
   136  
   137  	_, newDB, newDir, _, _, err := SetupSimulation("leveldb-app-sim-2", "Simulation-2")
   138  	require.NoError(t, err, "simulation setup failed")
   139  
   140  	defer func() {
   141  		newDB.Close()
   142  		require.NoError(t, os.RemoveAll(newDir))
   143  	}()
   144  
   145  	newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, FlagPeriodValue /*EmptyAppOptions{},*/, fauxMerkleModeOpt)
   146  	require.Equal(t, "SimApp", newApp.Name())
   147  
   148  	var genesisState GenesisState
   149  	err = json.Unmarshal(exported, &genesisState)
   150  	require.NoError(t, err)
   151  
   152  	ctxA := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
   153  	ctxB := newApp.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
   154  	newApp.mm.InitGenesis(ctxB, genesisState)
   155  
   156  	fmt.Printf("comparing stores...\n")
   157  
   158  	storeKeysPrefixes := []StoreKeysPrefixes{
   159  		{app.keys[authtypes.StoreKey], newApp.keys[authtypes.StoreKey], [][]byte{}},
   160  		{app.keys[stakingtypes.StoreKey], newApp.keys[stakingtypes.StoreKey],
   161  			[][]byte{
   162  				stakingtypes.UnbondingQueueKey, stakingtypes.RedelegationQueueKey, stakingtypes.ValidatorQueueKey,
   163  				stakingtypes.HistoricalInfoKey,
   164  			}}, // ordering may change but it doesn't matter
   165  		{app.keys[slashingtypes.StoreKey], newApp.keys[slashingtypes.StoreKey], [][]byte{}},
   166  		{app.keys[minttypes.StoreKey], newApp.keys[minttypes.StoreKey], [][]byte{}},
   167  		{app.keys[distrtypes.StoreKey], newApp.keys[distrtypes.StoreKey], [][]byte{}},
   168  		// todo check bank types
   169  		//		{app.keys[banktypes.StoreKey], newApp.keys[banktypes.StoreKey], [][]byte{banktypes.BalancesPrefix}},
   170  		{app.keys[banktypes.ModuleName], newApp.keys[banktypes.ModuleName], [][]byte{}},
   171  		//		{app.keys[paramtypes.StoreKey], newApp.keys[paramtypes.StoreKey], [][]byte{}},
   172  		{app.keys[paramtypes.ModuleName], newApp.keys[paramtypes.ModuleName], [][]byte{}},
   173  		{app.keys[govtypes.StoreKey], newApp.keys[govtypes.StoreKey], [][]byte{}},
   174  		{app.keys[evidencetypes.StoreKey], newApp.keys[evidencetypes.StoreKey], [][]byte{}},
   175  		{app.keys[capabilitytypes.StoreKey], newApp.keys[capabilitytypes.StoreKey], [][]byte{}},
   176  		{app.keys[ibchost.StoreKey], newApp.keys[ibchost.StoreKey], [][]byte{}},
   177  		{app.keys[ibctransfertypes.StoreKey], newApp.keys[ibctransfertypes.StoreKey], [][]byte{}},
   178  		//{app.keys[authzkeeper.StoreKey], newApp.keys[authzkeeper.StoreKey], [][]byte{}},
   179  	}
   180  
   181  	for _, skp := range storeKeysPrefixes {
   182  		storeA := ctxA.KVStore(skp.A)
   183  		storeB := ctxB.KVStore(skp.B)
   184  
   185  		failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes)
   186  		require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare")
   187  
   188  		fmt.Printf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B)
   189  		require.Equal(t, len(failedKVAs), 0, GetSimulationLog(skp.A.Name(), app.SimulationManager().StoreDecoders, failedKVAs, failedKVBs))
   190  	}
   191  }
   192  
   193  func TestAppSimulationAfterImport(t *testing.T) {
   194  	config, db, dir, logger, skip, err := SetupSimulation("leveldb-app-sim", "Simulation")
   195  	if skip {
   196  		t.Skip("skipping application simulation after import")
   197  	}
   198  	require.NoError(t, err, "simulation setup failed")
   199  
   200  	defer func() {
   201  		db.Close()
   202  		require.NoError(t, os.RemoveAll(dir))
   203  	}()
   204  
   205  	app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt)
   206  	require.Equal(t, "SimApp", app.Name())
   207  
   208  	// Run randomized simulation
   209  	stopEarly, simParams, simErr := simulation.SimulateFromSeed(
   210  		t,
   211  		os.Stdout,
   212  		app.BaseApp,
   213  		AppStateFn(*app.AppCodec(), app.SimulationManager()),
   214  		//		simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
   215  		SimulationOperations(app, *app.AppCodec().GetCdc(), config),
   216  		app.ModuleAccountAddrs(),
   217  		config,
   218  	)
   219  
   220  	// export state and simParams before the simulation error is checked
   221  	err = CheckExportSimulation(app, config, simParams)
   222  	require.NoError(t, err)
   223  	require.NoError(t, simErr)
   224  
   225  	if config.Commit {
   226  		PrintStats(db)
   227  	}
   228  
   229  	if stopEarly {
   230  		fmt.Println("can't export or import a zero-validator genesis, exiting test...")
   231  		return
   232  	}
   233  
   234  	fmt.Printf("exporting genesis...\n")
   235  
   236  	exported, _, err := app.ExportAppStateAndValidators(true, []string{})
   237  	require.NoError(t, err)
   238  
   239  	fmt.Printf("importing genesis...\n")
   240  
   241  	_, newDB, newDir, _, _, err := SetupSimulation("leveldb-app-sim-2", "Simulation-2")
   242  	require.NoError(t, err, "simulation setup failed")
   243  
   244  	defer func() {
   245  		newDB.Close()
   246  		require.NoError(t, os.RemoveAll(newDir))
   247  	}()
   248  
   249  	newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, FlagPeriodValue, fauxMerkleModeOpt)
   250  
   251  	require.Equal(t, "SimApp", newApp.Name())
   252  
   253  	newApp.InitChain(abci.RequestInitChain{
   254  		AppStateBytes: exported,
   255  	})
   256  
   257  	_, _, err = simulation.SimulateFromSeed(
   258  		t,
   259  		os.Stdout,
   260  		newApp.GetBaseApp(),
   261  		AppStateFn(*app.AppCodec(), app.SimulationManager()),
   262  		//		simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
   263  		SimulationOperations(newApp, *newApp.AppCodec().GetCdc(), config),
   264  		app.ModuleAccountAddrs(),
   265  		config,
   266  	)
   267  	require.NoError(t, err)
   268  }
   269  
   270  // TODO: Make another test for the fuzzer itself, which just has noOp txs
   271  // and doesn't depend on the application.
   272  func TestAppStateDeterminism(t *testing.T) {
   273  	if !FlagEnabledValue {
   274  		t.Skip("skipping application simulation")
   275  	}
   276  
   277  	config := NewConfigFromFlags()
   278  	config.InitialBlockHeight = 1
   279  	config.ExportParamsPath = ""
   280  	config.OnOperation = false
   281  	config.AllInvariants = false
   282  	config.ChainID = helpers.SimAppChainID
   283  
   284  	numSeeds := 3
   285  	numTimesToRunPerSeed := 5
   286  	appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
   287  
   288  	for i := 0; i < numSeeds; i++ {
   289  		config.Seed = rand.Int63()
   290  
   291  		for j := 0; j < numTimesToRunPerSeed; j++ {
   292  			var logger log.Logger
   293  			if FlagVerboseValue {
   294  				logger = log.TestingLogger()
   295  			} else {
   296  				logger = log.NewNopLogger()
   297  			}
   298  
   299  			db := dbm.NewMemDB()
   300  			// todo MakeTestEncodingConfig EmptyAppOptions
   301  			//	app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, interBlockCacheOpt())
   302  			app := NewSimApp(logger, db, nil, true, map[int64]bool{}, FlagPeriodValue, interBlockCacheOpt())
   303  
   304  			fmt.Printf(
   305  				"running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n",
   306  				config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
   307  			)
   308  
   309  			_, _, err := simulation.SimulateFromSeed(
   310  				t,
   311  				os.Stdout,
   312  				app.BaseApp,
   313  				AppStateFn(*app.AppCodec(), app.SimulationManager()),
   314  				//		simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
   315  				SimulationOperations(app, *app.AppCodec().GetCdc(), config),
   316  				app.ModuleAccountAddrs(),
   317  				config,
   318  			)
   319  			require.NoError(t, err)
   320  
   321  			if config.Commit {
   322  				PrintStats(db)
   323  			}
   324  
   325  			appHash := app.LastCommitID().Hash
   326  			appHashList[j] = appHash
   327  
   328  			if j != 0 {
   329  				require.Equal(
   330  					t, string(appHashList[0]), string(appHashList[j]),
   331  					"non-determinism in seed %d: %d/%d, attempt: %d/%d\n", config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
   332  				)
   333  			}
   334  		}
   335  	}
   336  }