github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/sdk/baseapp_test.go (about)

     1  package sdk
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"log/slog"
     8  	"os"
     9  	"reflect"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/gnolang/gno/tm2/pkg/amino"
    16  	abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types"
    17  	bft "github.com/gnolang/gno/tm2/pkg/bft/types"
    18  	dbm "github.com/gnolang/gno/tm2/pkg/db"
    19  	"github.com/gnolang/gno/tm2/pkg/db/memdb"
    20  	"github.com/gnolang/gno/tm2/pkg/sdk/testutils"
    21  	"github.com/gnolang/gno/tm2/pkg/std"
    22  	"github.com/gnolang/gno/tm2/pkg/store/dbadapter"
    23  	"github.com/gnolang/gno/tm2/pkg/store/iavl"
    24  	store "github.com/gnolang/gno/tm2/pkg/store/types"
    25  )
    26  
    27  var (
    28  	baseKey = store.NewStoreKey("base") // in all test apps
    29  	mainKey = store.NewStoreKey("main") // in all test apps
    30  )
    31  
    32  type (
    33  	msgCounter  = testutils.MsgCounter
    34  	msgCounter2 = testutils.MsgCounter2
    35  	msgNoRoute  = testutils.MsgNoRoute
    36  )
    37  
    38  const (
    39  	routeMsgCounter  = testutils.RouteMsgCounter
    40  	routeMsgCounter2 = testutils.RouteMsgCounter2
    41  )
    42  
    43  // txInt: used as counter in incrementing counter tests,
    44  // or as how much gas will be consumed in antehandler
    45  // (depending on anteHandler used in tests)
    46  func newTxCounter(txInt int64, msgInts ...int64) std.Tx {
    47  	msgs := make([]std.Msg, len(msgInts))
    48  
    49  	for i, msgInt := range msgInts {
    50  		msgs[i] = msgCounter{msgInt, false}
    51  	}
    52  
    53  	tx := std.Tx{Msgs: msgs}
    54  	setCounter(&tx, txInt)
    55  	setFailOnHandler(&tx, false)
    56  	return tx
    57  }
    58  
    59  func defaultLogger() *slog.Logger {
    60  	logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
    61  
    62  	return logger.With("module", "sdk/app")
    63  }
    64  
    65  func newBaseApp(name string, db dbm.DB, options ...func(*BaseApp)) *BaseApp {
    66  	logger := defaultLogger()
    67  	app := NewBaseApp(name, logger, db, baseKey, mainKey, options...)
    68  	app.MountStoreWithDB(baseKey, dbadapter.StoreConstructor, nil)
    69  	app.MountStoreWithDB(mainKey, iavl.StoreConstructor, nil)
    70  	return app
    71  }
    72  
    73  // simple one store baseapp
    74  func setupBaseApp(t *testing.T, options ...func(*BaseApp)) *BaseApp {
    75  	t.Helper()
    76  
    77  	db := memdb.NewMemDB()
    78  	app := newBaseApp(t.Name(), db, options...)
    79  	require.Equal(t, t.Name(), app.Name())
    80  	err := app.LoadLatestVersion()
    81  	require.Nil(t, err)
    82  	return app
    83  }
    84  
    85  func TestMountStores(t *testing.T) {
    86  	t.Parallel()
    87  
    88  	app := setupBaseApp(t)
    89  
    90  	// check both stores
    91  	store1 := app.cms.GetCommitStore(baseKey)
    92  	require.NotNil(t, store1)
    93  	store2 := app.cms.GetCommitStore(mainKey)
    94  	require.NotNil(t, store2)
    95  }
    96  
    97  // Test that we can make commits and then reload old versions.
    98  // Test that LoadLatestVersion actually does.
    99  func TestLoadVersion(t *testing.T) {
   100  	t.Parallel()
   101  
   102  	pruningOpt := SetPruningOptions(store.PruneSyncable)
   103  	name := t.Name()
   104  	db := memdb.NewMemDB()
   105  	app := newBaseApp(name, db, pruningOpt)
   106  
   107  	// make a cap key and mount the store
   108  	err := app.LoadLatestVersion() // needed to make stores non-nil
   109  	require.Nil(t, err)
   110  
   111  	emptyCommitID := store.CommitID{}
   112  
   113  	// fresh store has zero/empty last commit
   114  	lastHeight := app.LastBlockHeight()
   115  	lastID := app.LastCommitID()
   116  	require.Equal(t, int64(0), lastHeight)
   117  	require.Equal(t, emptyCommitID, lastID)
   118  
   119  	// execute a block, collect commit ID
   120  	header := &bft.Header{ChainID: "test-chain", Height: 1}
   121  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
   122  	res := app.Commit()
   123  	commitID1 := store.CommitID{1, res.Data}
   124  
   125  	// execute a block, collect commit ID
   126  	header = &bft.Header{ChainID: "test-chain", Height: 2}
   127  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
   128  	res = app.Commit()
   129  	commitID2 := store.CommitID{2, res.Data}
   130  
   131  	// reload with LoadLatestVersion
   132  	app = newBaseApp(name, db, pruningOpt)
   133  	err = app.LoadLatestVersion()
   134  	require.Nil(t, err)
   135  	testLoadVersionHelper(t, app, int64(2), commitID2)
   136  
   137  	// reload with LoadVersion, see if you can commit the same block and get
   138  	// the same result
   139  	app = newBaseApp(name, db, pruningOpt)
   140  	err = app.LoadVersion(1)
   141  	require.Nil(t, err)
   142  	testLoadVersionHelper(t, app, int64(1), commitID1)
   143  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
   144  	app.Commit()
   145  	testLoadVersionHelper(t, app, int64(2), commitID2)
   146  }
   147  
   148  func TestAppVersionSetterGetter(t *testing.T) {
   149  	t.Parallel()
   150  
   151  	pruningOpt := SetPruningOptions(store.PruneSyncable)
   152  	name := t.Name()
   153  	db := memdb.NewMemDB()
   154  	app := newBaseApp(name, db, pruningOpt)
   155  
   156  	require.Equal(t, "", app.AppVersion())
   157  	res := app.Query(abci.RequestQuery{Path: ".app/version"})
   158  	require.True(t, res.IsOK())
   159  	require.Equal(t, "", string(res.Value))
   160  
   161  	versionString := "1.0.0"
   162  	app.SetAppVersion(versionString)
   163  	require.Equal(t, versionString, app.AppVersion())
   164  	res = app.Query(abci.RequestQuery{Path: ".app/version"})
   165  	require.True(t, res.IsOK())
   166  	require.Equal(t, versionString, string(res.Value))
   167  }
   168  
   169  func TestLoadVersionInvalid(t *testing.T) {
   170  	t.Parallel()
   171  
   172  	pruningOpt := SetPruningOptions(store.PruneSyncable)
   173  	name := t.Name()
   174  	db := memdb.NewMemDB()
   175  	app := newBaseApp(name, db, pruningOpt)
   176  
   177  	err := app.LoadLatestVersion()
   178  	require.Nil(t, err)
   179  
   180  	// require error when loading an invalid version
   181  	err = app.LoadVersion(-1)
   182  	require.Error(t, err)
   183  
   184  	header := &bft.Header{ChainID: "test-chain", Height: 1}
   185  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
   186  	res := app.Commit()
   187  	commitID1 := store.CommitID{1, res.Data}
   188  
   189  	// create a new app with the stores mounted under the same cap key
   190  	app = newBaseApp(name, db, pruningOpt)
   191  
   192  	// require we can load the latest version
   193  	err = app.LoadVersion(1)
   194  	require.Nil(t, err)
   195  	testLoadVersionHelper(t, app, int64(1), commitID1)
   196  
   197  	// require error when loading an invalid version
   198  	err = app.LoadVersion(2)
   199  	require.Error(t, err)
   200  }
   201  
   202  func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, expectedID store.CommitID) {
   203  	t.Helper()
   204  
   205  	lastHeight := app.LastBlockHeight()
   206  	lastID := app.LastCommitID()
   207  	require.Equal(t, expectedHeight, lastHeight)
   208  	require.Equal(t, expectedID, lastID)
   209  }
   210  
   211  func TestOptionFunction(t *testing.T) {
   212  	t.Parallel()
   213  
   214  	db := memdb.NewMemDB()
   215  	bap := newBaseApp("starting name", db, testChangeNameHelper("new name"))
   216  	require.Equal(t, bap.name, "new name", "BaseApp should have had name changed via option function")
   217  }
   218  
   219  func testChangeNameHelper(name string) func(*BaseApp) {
   220  	return func(bap *BaseApp) {
   221  		bap.name = name
   222  	}
   223  }
   224  
   225  // Test that Info returns the latest committed state.
   226  func TestInfo(t *testing.T) {
   227  	t.Parallel()
   228  
   229  	db := memdb.NewMemDB()
   230  	app := newBaseApp(t.Name(), db)
   231  
   232  	// ----- test an empty response -------
   233  	reqInfo := abci.RequestInfo{}
   234  	res := app.Info(reqInfo)
   235  
   236  	// should be empty
   237  	assert.Equal(t, "", res.AppVersion)
   238  	assert.Equal(t, t.Name(), string(res.Data))
   239  	assert.Equal(t, int64(0), res.LastBlockHeight)
   240  	require.Equal(t, []uint8(nil), res.LastBlockAppHash)
   241  
   242  	// ----- test a proper response -------
   243  	// TODO
   244  }
   245  
   246  func TestBaseAppOptionSeal(t *testing.T) {
   247  	t.Parallel()
   248  
   249  	app := setupBaseApp(t)
   250  
   251  	require.Panics(t, func() {
   252  		app.SetName("")
   253  	})
   254  	require.Panics(t, func() {
   255  		app.SetAppVersion("")
   256  	})
   257  	require.Panics(t, func() {
   258  		app.SetDB(nil)
   259  	})
   260  	require.Panics(t, func() {
   261  		app.SetCMS(nil)
   262  	})
   263  	require.Panics(t, func() {
   264  		app.SetInitChainer(nil)
   265  	})
   266  	require.Panics(t, func() {
   267  		app.SetBeginBlocker(nil)
   268  	})
   269  	require.Panics(t, func() {
   270  		app.SetEndBlocker(nil)
   271  	})
   272  	require.Panics(t, func() {
   273  		app.SetAnteHandler(nil)
   274  	})
   275  }
   276  
   277  func TestSetMinGasPrices(t *testing.T) {
   278  	t.Parallel()
   279  
   280  	minGasPrices, err := ParseGasPrices("5000stake/10gas")
   281  	require.Nil(t, err)
   282  	db := memdb.NewMemDB()
   283  	app := newBaseApp(t.Name(), db, SetMinGasPrices("5000stake/10gas"))
   284  	require.Equal(t, minGasPrices, app.minGasPrices)
   285  }
   286  
   287  func TestInitChainer(t *testing.T) {
   288  	t.Parallel()
   289  
   290  	name := t.Name()
   291  	// keep the db and logger ourselves so
   292  	// we can reload the same  app later
   293  	db := memdb.NewMemDB()
   294  	app := newBaseApp(name, db)
   295  
   296  	// set a value in the store on init chain
   297  	key, value := []byte("hello"), []byte("goodbye")
   298  	var initChainer InitChainer = func(ctx Context, req abci.RequestInitChain) abci.ResponseInitChain {
   299  		store := ctx.Store(mainKey)
   300  		store.Set(key, value)
   301  		return abci.ResponseInitChain{}
   302  	}
   303  
   304  	query := abci.RequestQuery{
   305  		Path: ".store/main/key",
   306  		Data: key,
   307  	}
   308  
   309  	// initChainer is nil - nothing happens
   310  	app.InitChain(abci.RequestInitChain{ChainID: "test-chain"})
   311  	res := app.Query(query)
   312  	require.Equal(t, 0, len(res.Value))
   313  
   314  	// set initChainer and try again - should see the value
   315  	app.SetInitChainer(initChainer)
   316  
   317  	// stores are mounted and private members are set - sealing baseapp
   318  	err := app.LoadLatestVersion() // needed to make stores non-nil
   319  	require.Nil(t, err)
   320  	require.Equal(t, int64(0), app.LastBlockHeight())
   321  
   322  	app.InitChain(abci.RequestInitChain{AppState: nil, ChainID: "test-chain-id"}) // must have valid JSON genesis file, even if empty
   323  
   324  	// assert that chainID is set correctly in InitChain
   325  	chainID := app.deliverState.ctx.ChainID()
   326  	require.Equal(t, "test-chain-id", chainID, "ChainID in deliverState not set correctly in InitChain")
   327  
   328  	chainID = app.checkState.ctx.ChainID()
   329  	require.Equal(t, "test-chain-id", chainID, "ChainID in checkState not set correctly in InitChain")
   330  
   331  	app.Commit()
   332  	res = app.Query(query)
   333  	require.Equal(t, int64(1), app.LastBlockHeight())
   334  	require.Equal(t, value, res.Value)
   335  
   336  	// reload app
   337  	app = newBaseApp(name, db)
   338  	app.SetInitChainer(initChainer)
   339  	err = app.LoadLatestVersion() // needed to make stores non-nil
   340  	require.Nil(t, err)
   341  	require.Equal(t, int64(1), app.LastBlockHeight())
   342  
   343  	// ensure we can still query after reloading
   344  	res = app.Query(query)
   345  	require.Equal(t, value, res.Value)
   346  
   347  	// commit and ensure we can still query
   348  	header := &bft.Header{ChainID: "test-chain", Height: app.LastBlockHeight() + 1}
   349  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
   350  	app.Commit()
   351  
   352  	res = app.Query(query)
   353  	require.Equal(t, value, res.Value)
   354  }
   355  
   356  type testTxData struct {
   357  	FailOnAnte bool
   358  	Counter    int64
   359  }
   360  
   361  func getFailOnAnte(tx Tx) bool {
   362  	var testdata testTxData
   363  	amino.MustUnmarshalJSON([]byte(tx.Memo), &testdata)
   364  	return testdata.FailOnAnte
   365  }
   366  
   367  func setFailOnAnte(tx *Tx, fail bool) {
   368  	var testdata testTxData
   369  	if tx.Memo == "" {
   370  		tx.Memo = "{}"
   371  	}
   372  	amino.MustUnmarshalJSON([]byte(tx.Memo), &testdata)
   373  	testdata.FailOnAnte = fail
   374  	tx.Memo = string(amino.MustMarshalJSON(testdata))
   375  }
   376  
   377  func getCounter(tx Tx) int64 {
   378  	var testdata testTxData
   379  	amino.MustUnmarshalJSON([]byte(tx.Memo), &testdata)
   380  	return testdata.Counter
   381  }
   382  
   383  func setCounter(tx *Tx, counter int64) {
   384  	var testdata testTxData
   385  	if tx.Memo == "" {
   386  		tx.Memo = "{}"
   387  	}
   388  	amino.MustUnmarshalJSON([]byte(tx.Memo), &testdata)
   389  	testdata.Counter = counter
   390  	tx.Memo = string(amino.MustMarshalJSON(testdata))
   391  }
   392  
   393  func setFailOnHandler(tx *Tx, fail bool) {
   394  	for i, msg := range tx.Msgs {
   395  		tx.Msgs[i] = msgCounter{msg.(msgCounter).Counter, fail}
   396  	}
   397  }
   398  
   399  func anteHandlerTxTest(t *testing.T, capKey store.StoreKey, storeKey []byte) AnteHandler {
   400  	t.Helper()
   401  
   402  	return func(ctx Context, tx std.Tx, simulate bool) (newCtx Context, res Result, abort bool) {
   403  		store := ctx.Store(capKey)
   404  		if getFailOnAnte(tx) {
   405  			res.Error = ABCIError(std.ErrInternal("ante handler failure"))
   406  			return newCtx, res, true
   407  		}
   408  
   409  		res = incrementingCounter(t, store, storeKey, getCounter(tx))
   410  		newCtx = ctx
   411  		return
   412  	}
   413  }
   414  
   415  type testHandler struct {
   416  	process func(Context, Msg) Result
   417  	query   func(Context, abci.RequestQuery) abci.ResponseQuery
   418  }
   419  
   420  func (th testHandler) Process(ctx Context, msg Msg) Result {
   421  	return th.process(ctx, msg)
   422  }
   423  
   424  func (th testHandler) Query(ctx Context, req abci.RequestQuery) abci.ResponseQuery {
   425  	return th.query(ctx, req)
   426  }
   427  
   428  func newTestHandler(proc func(Context, Msg) Result) Handler {
   429  	return testHandler{
   430  		process: proc,
   431  	}
   432  }
   433  
   434  type msgCounterHandler struct {
   435  	t          *testing.T
   436  	capKey     store.StoreKey
   437  	deliverKey []byte
   438  }
   439  
   440  func newMsgCounterHandler(t *testing.T, capKey store.StoreKey, deliverKey []byte) Handler {
   441  	t.Helper()
   442  
   443  	return msgCounterHandler{t, capKey, deliverKey}
   444  }
   445  
   446  func (mch msgCounterHandler) Process(ctx Context, msg Msg) (res Result) {
   447  	store := ctx.Store(mch.capKey)
   448  	var msgCount int64
   449  	switch m := msg.(type) {
   450  	case msgCounter:
   451  		if m.FailOnHandler {
   452  			res.Error = ABCIError(std.ErrInternal("message handler failure"))
   453  			return
   454  		}
   455  		msgCount = m.Counter
   456  	case msgCounter2:
   457  		msgCount = m.Counter
   458  	default:
   459  		panic(fmt.Sprint("unexpected msg type", reflect.TypeOf(msg)))
   460  	}
   461  	return incrementingCounter(mch.t, store, mch.deliverKey, msgCount)
   462  }
   463  
   464  func (mch msgCounterHandler) Query(ctx Context, req abci.RequestQuery) abci.ResponseQuery {
   465  	panic("should not happen")
   466  }
   467  
   468  func getIntFromStore(store store.Store, key []byte) int64 {
   469  	bz := store.Get(key)
   470  	if len(bz) == 0 {
   471  		return 0
   472  	}
   473  	i, err := binary.ReadVarint(bytes.NewBuffer(bz))
   474  	if err != nil {
   475  		panic(err)
   476  	}
   477  	return i
   478  }
   479  
   480  func setIntOnStore(store store.Store, key []byte, i int64) {
   481  	bz := make([]byte, 8)
   482  	n := binary.PutVarint(bz, i)
   483  	store.Set(key, bz[:n])
   484  }
   485  
   486  // check counter matches what's in store.
   487  // increment and store
   488  func incrementingCounter(t *testing.T, store store.Store, counterKey []byte, counter int64) (res Result) {
   489  	t.Helper()
   490  
   491  	storedCounter := getIntFromStore(store, counterKey)
   492  	require.Equal(t, storedCounter, counter)
   493  	setIntOnStore(store, counterKey, counter+1)
   494  	return
   495  }
   496  
   497  // ---------------------------------------------------------------------
   498  // Tx processing - CheckTx, DeliverTx, SimulateTx.
   499  // These tests use the serialized tx as input, while most others will use the
   500  // Check(), Deliver(), Simulate() methods directly.
   501  // Ensure that Check/Deliver/Simulate work as expected with the store.
   502  
   503  // Test that successive CheckTx can see each others' effects
   504  // on the store within a block, and that the CheckTx state
   505  // gets reset to the latest committed state during Commit
   506  func TestCheckTx(t *testing.T) {
   507  	t.Parallel()
   508  
   509  	// This ante handler reads the key and checks that the value matches the current counter.
   510  	// This ensures changes to the kvstore persist across successive CheckTx.
   511  	counterKey := []byte("counter-key")
   512  
   513  	anteOpt := func(bapp *BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, mainKey, counterKey)) }
   514  	routerOpt := func(bapp *BaseApp) {
   515  		// TODO: can remove this once CheckTx doesn't process msgs.
   516  		bapp.Router().AddRoute(routeMsgCounter, newTestHandler(func(ctx Context, msg Msg) Result { return Result{} }))
   517  	}
   518  
   519  	app := setupBaseApp(t, anteOpt, routerOpt)
   520  
   521  	nTxs := int64(5)
   522  	app.InitChain(abci.RequestInitChain{ChainID: "test-chain"})
   523  
   524  	for i := int64(0); i < nTxs; i++ {
   525  		tx := newTxCounter(i, 0)
   526  		txBytes, err := amino.Marshal(tx)
   527  		require.NoError(t, err)
   528  		r := app.CheckTx(abci.RequestCheckTx{Tx: txBytes})
   529  		assert.True(t, r.IsOK(), fmt.Sprintf("%v", r))
   530  	}
   531  
   532  	checkStateStore := app.checkState.ctx.Store(mainKey)
   533  	storedCounter := getIntFromStore(checkStateStore, counterKey)
   534  
   535  	// Ensure AnteHandler ran
   536  	require.Equal(t, nTxs, storedCounter)
   537  
   538  	// If a block is committed, CheckTx state should be reset.
   539  	header := &bft.Header{ChainID: "test-chain", Height: 1}
   540  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
   541  	app.EndBlock(abci.RequestEndBlock{})
   542  	app.Commit()
   543  
   544  	checkStateStore = app.checkState.ctx.Store(mainKey)
   545  	storedBytes := checkStateStore.Get(counterKey)
   546  	require.Nil(t, storedBytes)
   547  }
   548  
   549  // Test that successive DeliverTx can see each others' effects
   550  // on the store, both within and across blocks.
   551  func TestDeliverTx(t *testing.T) {
   552  	t.Parallel()
   553  
   554  	// test increments in the ante
   555  	anteKey := []byte("ante-key")
   556  	anteOpt := func(bapp *BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, mainKey, anteKey)) }
   557  
   558  	// test increments in the handler
   559  	deliverKey := []byte("deliver-key")
   560  	routerOpt := func(bapp *BaseApp) {
   561  		bapp.Router().AddRoute(routeMsgCounter, newMsgCounterHandler(t, mainKey, deliverKey))
   562  	}
   563  
   564  	app := setupBaseApp(t, anteOpt, routerOpt)
   565  	app.InitChain(abci.RequestInitChain{ChainID: "test-chain"})
   566  
   567  	nBlocks := 3
   568  	txPerHeight := 5
   569  
   570  	for blockN := 0; blockN < nBlocks; blockN++ {
   571  		header := &bft.Header{ChainID: "test-chain", Height: int64(blockN) + 1}
   572  		app.BeginBlock(abci.RequestBeginBlock{Header: header})
   573  
   574  		for i := 0; i < txPerHeight; i++ {
   575  			counter := int64(blockN*txPerHeight + i)
   576  			tx := newTxCounter(counter, counter)
   577  
   578  			txBytes, err := amino.Marshal(tx)
   579  			require.NoError(t, err)
   580  
   581  			res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
   582  			require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
   583  		}
   584  
   585  		app.EndBlock(abci.RequestEndBlock{})
   586  		app.Commit()
   587  	}
   588  }
   589  
   590  // One call to DeliverTx should process all the messages, in order.
   591  func TestMultiMsgDeliverTx(t *testing.T) {
   592  	t.Parallel()
   593  
   594  	// increment the tx counter
   595  	anteKey := []byte("ante-key")
   596  	anteOpt := func(bapp *BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, mainKey, anteKey)) }
   597  
   598  	// increment the msg counter
   599  	deliverKey := []byte("deliver-key")
   600  	deliverKey2 := []byte("deliver-key2")
   601  	routerOpt := func(bapp *BaseApp) {
   602  		bapp.Router().AddRoute(routeMsgCounter, newMsgCounterHandler(t, mainKey, deliverKey))
   603  		bapp.Router().AddRoute(routeMsgCounter2, newMsgCounterHandler(t, mainKey, deliverKey2))
   604  	}
   605  
   606  	app := setupBaseApp(t, anteOpt, routerOpt)
   607  
   608  	// run a multi-msg tx
   609  	// with all msgs the same route
   610  
   611  	header := &bft.Header{ChainID: "test-chain", Height: 1}
   612  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
   613  	tx := newTxCounter(0, 0, 1, 2)
   614  	txBytes, err := amino.Marshal(tx)
   615  	require.NoError(t, err)
   616  	res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
   617  	require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
   618  
   619  	store := app.deliverState.ctx.Store(mainKey)
   620  
   621  	// tx counter only incremented once
   622  	txCounter := getIntFromStore(store, anteKey)
   623  	require.Equal(t, int64(1), txCounter)
   624  
   625  	// msg counter incremented three times
   626  	msgCounter := getIntFromStore(store, deliverKey)
   627  	require.Equal(t, int64(3), msgCounter)
   628  
   629  	// replace the second message with a msgCounter2
   630  
   631  	tx = newTxCounter(1, 3)
   632  	tx.Msgs = append(tx.Msgs, msgCounter2{0})
   633  	tx.Msgs = append(tx.Msgs, msgCounter2{1})
   634  	txBytes, err = amino.Marshal(tx)
   635  	require.NoError(t, err)
   636  	res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
   637  	require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
   638  
   639  	store = app.deliverState.ctx.Store(mainKey)
   640  
   641  	// tx counter only incremented once
   642  	txCounter = getIntFromStore(store, anteKey)
   643  	require.Equal(t, int64(2), txCounter)
   644  
   645  	// original counter increments by one
   646  	// new counter increments by two
   647  	msgCounter = getIntFromStore(store, deliverKey)
   648  	require.Equal(t, int64(4), msgCounter)
   649  	msgCounter2 := getIntFromStore(store, deliverKey2)
   650  	require.Equal(t, int64(2), msgCounter2)
   651  }
   652  
   653  // Simulate a transaction that uses gas to compute the gas.
   654  // Simulate() and Query(".app/simulate", txBytes) should give
   655  // the same results.
   656  func TestSimulateTx(t *testing.T) {
   657  	t.Parallel()
   658  
   659  	gasConsumed := int64(5)
   660  
   661  	anteOpt := func(bapp *BaseApp) {
   662  		bapp.SetAnteHandler(func(ctx Context, tx Tx, simulate bool) (newCtx Context, res Result, abort bool) {
   663  			limit := gasConsumed
   664  			newCtx = ctx.WithGasMeter(store.NewGasMeter(limit))
   665  			return
   666  		})
   667  	}
   668  
   669  	routerOpt := func(bapp *BaseApp) {
   670  		bapp.Router().AddRoute(routeMsgCounter, newTestHandler(func(ctx Context, msg Msg) Result {
   671  			ctx.GasMeter().ConsumeGas(gasConsumed, "test")
   672  			return Result{GasUsed: ctx.GasMeter().GasConsumed()}
   673  		}))
   674  	}
   675  
   676  	app := setupBaseApp(t, anteOpt, routerOpt)
   677  
   678  	app.InitChain(abci.RequestInitChain{ChainID: "test-chain"})
   679  
   680  	nBlocks := 3
   681  	for blockN := 0; blockN < nBlocks; blockN++ {
   682  		count := int64(blockN + 1)
   683  		header := &bft.Header{ChainID: "test-chain", Height: count}
   684  		app.BeginBlock(abci.RequestBeginBlock{Header: header})
   685  
   686  		tx := newTxCounter(count, count)
   687  		txBytes, err := amino.Marshal(tx)
   688  		require.Nil(t, err)
   689  
   690  		// simulate a message, check gas reported
   691  		result := app.Simulate(txBytes, tx)
   692  		require.True(t, result.IsOK(), result.Log)
   693  		require.Equal(t, gasConsumed, result.GasUsed)
   694  
   695  		// simulate again, same result
   696  		result = app.Simulate(txBytes, tx)
   697  		require.True(t, result.IsOK(), result.Log)
   698  		require.Equal(t, gasConsumed, result.GasUsed)
   699  
   700  		// simulate by calling Query with encoded tx
   701  		query := abci.RequestQuery{
   702  			Path: ".app/simulate",
   703  			Data: txBytes,
   704  		}
   705  		queryResult := app.Query(query)
   706  		require.True(t, queryResult.IsOK(), queryResult.Log)
   707  
   708  		var res Result
   709  		amino.MustUnmarshal(queryResult.Value, &res)
   710  		require.Nil(t, err, "Result unmarshalling failed")
   711  		require.True(t, res.IsOK(), res.Log)
   712  		require.Equal(t, gasConsumed, res.GasUsed, res.Log)
   713  		app.EndBlock(abci.RequestEndBlock{})
   714  		app.Commit()
   715  	}
   716  }
   717  
   718  func TestRunInvalidTransaction(t *testing.T) {
   719  	t.Parallel()
   720  
   721  	anteOpt := func(bapp *BaseApp) {
   722  		bapp.SetAnteHandler(func(ctx Context, tx Tx, simulate bool) (newCtx Context, res Result, abort bool) {
   723  			newCtx = ctx
   724  			return
   725  		})
   726  	}
   727  	routerOpt := func(bapp *BaseApp) {
   728  		bapp.Router().AddRoute(routeMsgCounter, newTestHandler(func(ctx Context, msg Msg) (res Result) { return }))
   729  	}
   730  
   731  	app := setupBaseApp(t, anteOpt, routerOpt)
   732  
   733  	header := &bft.Header{ChainID: "test-chain", Height: 1}
   734  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
   735  
   736  	// Transaction with no messages
   737  	{
   738  		emptyTx := std.Tx{}
   739  		err := app.Deliver(emptyTx)
   740  		_, ok := err.Error.(std.UnknownRequestError)
   741  		require.True(t, ok)
   742  	}
   743  
   744  	// Transaction where ValidateBasic fails
   745  	{
   746  		testCases := []struct {
   747  			tx   std.Tx
   748  			fail bool
   749  		}{
   750  			{newTxCounter(0, 0), false},
   751  			{newTxCounter(-1, 0), false},
   752  			{newTxCounter(100, 100), false},
   753  			{newTxCounter(100, 5, 4, 3, 2, 1), false},
   754  
   755  			{newTxCounter(0, -1), true},
   756  			{newTxCounter(0, 1, -2), true},
   757  			{newTxCounter(0, 1, 2, -10, 5), true},
   758  		}
   759  
   760  		for _, testCase := range testCases {
   761  			tx := testCase.tx
   762  			res := app.Deliver(tx)
   763  			if testCase.fail {
   764  				_, ok := res.Error.(std.InvalidSequenceError)
   765  				require.True(t, ok)
   766  			} else {
   767  				require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
   768  			}
   769  		}
   770  	}
   771  
   772  	// Transaction with no known route
   773  	{
   774  		unknownRouteTx := std.Tx{Msgs: []Msg{msgNoRoute{}}}
   775  		err := app.Deliver(unknownRouteTx)
   776  		_, ok := err.Error.(std.UnknownRequestError)
   777  		require.True(t, ok)
   778  
   779  		unknownRouteTx = std.Tx{Msgs: []Msg{msgCounter{}, msgNoRoute{}}}
   780  		err = app.Deliver(unknownRouteTx)
   781  		_, ok = err.Error.(std.UnknownRequestError)
   782  		require.True(t, ok)
   783  	}
   784  
   785  	// Transaction with an unregistered message
   786  	{
   787  		txBytes := []byte{0xFF, 0xFF, 0xFF}
   788  		res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
   789  		_, ok := res.Error.(std.TxDecodeError)
   790  		require.True(t, ok)
   791  	}
   792  }
   793  
   794  // Test that transactions exceeding gas limits fail
   795  func TestTxGasLimits(t *testing.T) {
   796  	t.Parallel()
   797  
   798  	gasGranted := int64(10)
   799  	anteOpt := func(bapp *BaseApp) {
   800  		bapp.SetAnteHandler(func(ctx Context, tx Tx, simulate bool) (newCtx Context, res Result, abort bool) {
   801  			gmeter := store.NewPassthroughGasMeter(
   802  				ctx.GasMeter(),
   803  				gasGranted,
   804  			)
   805  			newCtx = ctx.WithGasMeter(gmeter)
   806  
   807  			count := getCounter(tx)
   808  			newCtx.GasMeter().ConsumeGas(count, "counter-ante")
   809  			res = Result{
   810  				GasWanted: gasGranted,
   811  			}
   812  			return
   813  		})
   814  	}
   815  
   816  	routerOpt := func(bapp *BaseApp) {
   817  		bapp.Router().AddRoute(routeMsgCounter, newTestHandler(func(ctx Context, msg Msg) Result {
   818  			count := msg.(msgCounter).Counter
   819  			ctx.GasMeter().ConsumeGas(count, "counter-handler")
   820  			return Result{}
   821  		}))
   822  	}
   823  
   824  	app := setupBaseApp(t, anteOpt, routerOpt)
   825  
   826  	header := &bft.Header{ChainID: "test-chain", Height: 1}
   827  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
   828  
   829  	testCases := []struct {
   830  		tx      std.Tx
   831  		gasUsed int64
   832  		fail    bool
   833  	}{
   834  		{newTxCounter(0, 0), 0, false},
   835  		{newTxCounter(1, 1), 2, false},
   836  		{newTxCounter(9, 1), 10, false},
   837  		{newTxCounter(1, 9), 10, false},
   838  		{newTxCounter(10, 0), 10, false},
   839  		{newTxCounter(0, 10), 10, false},
   840  		{newTxCounter(0, 8, 2), 10, false},
   841  		{newTxCounter(0, 5, 1, 1, 1, 1, 1), 10, false},
   842  		{newTxCounter(0, 5, 1, 1, 1, 1), 9, false},
   843  
   844  		{newTxCounter(9, 2), 11, true},
   845  		{newTxCounter(2, 9), 11, true},
   846  		{newTxCounter(9, 1, 1), 11, true},
   847  		{newTxCounter(1, 8, 1, 1), 11, true},
   848  		{newTxCounter(11, 0), 11, true},
   849  		{newTxCounter(0, 11), 11, true},
   850  		{newTxCounter(0, 5, 11), 16, true},
   851  	}
   852  
   853  	for i, tc := range testCases {
   854  		tx := tc.tx
   855  		res := app.Deliver(tx)
   856  
   857  		// check gas used and wanted
   858  		require.Equal(t, tc.gasUsed, res.GasUsed, fmt.Sprintf("%d: %v, %v", i, tc, res))
   859  
   860  		// check for out of gas
   861  		if !tc.fail {
   862  			require.True(t, res.IsOK(), fmt.Sprintf("%d: %v, %v", i, tc, res))
   863  		} else {
   864  			_, ok := res.Error.(std.OutOfGasError)
   865  			require.True(t, ok, fmt.Sprintf("%d: %v, %v", i, tc, res))
   866  		}
   867  	}
   868  }
   869  
   870  // Test that transactions exceeding gas limits fail
   871  func TestMaxBlockGasLimits(t *testing.T) {
   872  	t.Parallel()
   873  
   874  	gasGranted := int64(10)
   875  	anteOpt := func(bapp *BaseApp) {
   876  		bapp.SetAnteHandler(func(ctx Context, tx Tx, simulate bool) (newCtx Context, res Result, abort bool) {
   877  			gmeter := store.NewPassthroughGasMeter(
   878  				ctx.GasMeter(),
   879  				gasGranted,
   880  			)
   881  			newCtx = ctx.WithGasMeter(gmeter)
   882  
   883  			count := getCounter(tx)
   884  			newCtx.GasMeter().ConsumeGas(count, "counter-ante")
   885  			res = Result{
   886  				GasWanted: gasGranted,
   887  			}
   888  			return
   889  		})
   890  	}
   891  
   892  	routerOpt := func(bapp *BaseApp) {
   893  		bapp.Router().AddRoute(routeMsgCounter, newTestHandler(func(ctx Context, msg Msg) Result {
   894  			count := msg.(msgCounter).Counter
   895  			ctx.GasMeter().ConsumeGas(count, "counter-handler")
   896  			return Result{}
   897  		}))
   898  	}
   899  
   900  	app := setupBaseApp(t, anteOpt, routerOpt)
   901  	app.InitChain(abci.RequestInitChain{
   902  		ChainID: "test-chain",
   903  		ConsensusParams: &abci.ConsensusParams{
   904  			Block: &abci.BlockParams{
   905  				MaxGas: 100,
   906  			},
   907  		},
   908  	})
   909  
   910  	testCases := []struct {
   911  		tx                std.Tx
   912  		numDelivers       int
   913  		gasUsedPerDeliver int64
   914  		fail              bool
   915  		failAfterDeliver  int
   916  	}{
   917  		{newTxCounter(0, 0), 0, 0, false, 0},
   918  		{newTxCounter(9, 1), 2, 10, false, 0},
   919  		{newTxCounter(10, 0), 3, 10, false, 0},
   920  		{newTxCounter(10, 0), 10, 10, false, 0},
   921  		{newTxCounter(2, 7), 11, 9, false, 0},
   922  		{newTxCounter(10, 0), 10, 10, false, 0}, // hit the limit but pass
   923  
   924  		{newTxCounter(10, 0), 11, 10, true, 10},
   925  		{newTxCounter(10, 0), 15, 10, true, 10},
   926  		{newTxCounter(9, 0), 12, 9, true, 11}, // fly past the limit
   927  	}
   928  
   929  	for i, tc := range testCases {
   930  		fmt.Printf("debug i: %v\n", i)
   931  		tx := tc.tx
   932  
   933  		// reset the block gas
   934  		header := &bft.Header{ChainID: "test-chain", Height: app.LastBlockHeight() + 1}
   935  		app.BeginBlock(abci.RequestBeginBlock{Header: header})
   936  
   937  		// execute the transaction multiple times
   938  		for j := 0; j < tc.numDelivers; j++ {
   939  			res := app.Deliver(tx)
   940  
   941  			ctx := app.getState(RunTxModeDeliver).ctx
   942  			blockGasUsed := ctx.BlockGasMeter().GasConsumed()
   943  
   944  			// check for failed transactions
   945  			if tc.fail && (j+1) > tc.failAfterDeliver {
   946  				_, ok := res.Error.(std.OutOfGasError)
   947  				require.True(t, ok, fmt.Sprintf("%d: %v, %v", i, tc, res))
   948  				require.True(t, ctx.BlockGasMeter().IsOutOfGas())
   949  			} else {
   950  				// check gas used and wanted
   951  				expBlockGasUsed := tc.gasUsedPerDeliver * int64(j+1)
   952  				require.Equal(t, expBlockGasUsed, blockGasUsed,
   953  					fmt.Sprintf("%d,%d: %v, %v, %v, %v", i, j, tc, expBlockGasUsed, blockGasUsed, res))
   954  
   955  				require.True(t, res.IsOK(), fmt.Sprintf("%d,%d: %v, %v", i, j, tc, res))
   956  				require.False(t, ctx.BlockGasMeter().IsPastLimit())
   957  			}
   958  		}
   959  	}
   960  }
   961  
   962  func TestBaseAppAnteHandler(t *testing.T) {
   963  	t.Parallel()
   964  
   965  	anteKey := []byte("ante-key")
   966  	anteOpt := func(bapp *BaseApp) {
   967  		bapp.SetAnteHandler(anteHandlerTxTest(t, mainKey, anteKey))
   968  	}
   969  
   970  	deliverKey := []byte("deliver-key")
   971  	routerOpt := func(bapp *BaseApp) {
   972  		bapp.Router().AddRoute(routeMsgCounter, newMsgCounterHandler(t, mainKey, deliverKey))
   973  	}
   974  
   975  	app := setupBaseApp(t, anteOpt, routerOpt)
   976  
   977  	app.InitChain(abci.RequestInitChain{ChainID: "test-chain"})
   978  
   979  	header := &bft.Header{ChainID: "test-chain", Height: app.LastBlockHeight() + 1}
   980  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
   981  
   982  	// execute a tx that will fail ante handler execution
   983  	//
   984  	// NOTE: State should not be mutated here. This will be implicitly checked by
   985  	// the next txs ante handler execution (anteHandlerTxTest).
   986  	tx := newTxCounter(0, 0)
   987  	setFailOnAnte(&tx, true)
   988  	txBytes, err := amino.Marshal(tx)
   989  	require.NoError(t, err)
   990  	res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
   991  	require.False(t, res.IsOK(), fmt.Sprintf("%v", res))
   992  
   993  	ctx := app.getState(RunTxModeDeliver).ctx
   994  	store := ctx.Store(mainKey)
   995  	require.Equal(t, int64(0), getIntFromStore(store, anteKey))
   996  
   997  	// execute at tx that will pass the ante handler (the checkTx state should
   998  	// mutate) but will fail the message handler
   999  	tx = newTxCounter(0, 0)
  1000  	setFailOnHandler(&tx, true)
  1001  
  1002  	txBytes, err = amino.Marshal(tx)
  1003  	require.NoError(t, err)
  1004  
  1005  	res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
  1006  	require.False(t, res.IsOK(), fmt.Sprintf("%v", res))
  1007  
  1008  	ctx = app.getState(RunTxModeDeliver).ctx
  1009  	store = ctx.Store(mainKey)
  1010  	require.Equal(t, int64(1), getIntFromStore(store, anteKey))
  1011  	require.Equal(t, int64(0), getIntFromStore(store, deliverKey))
  1012  
  1013  	// execute a successful ante handler and message execution where state is
  1014  	// implicitly checked by previous tx executions
  1015  	tx = newTxCounter(1, 0)
  1016  
  1017  	txBytes, err = amino.Marshal(tx)
  1018  	require.NoError(t, err)
  1019  
  1020  	res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
  1021  	require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
  1022  
  1023  	ctx = app.getState(RunTxModeDeliver).ctx
  1024  	store = ctx.Store(mainKey)
  1025  	require.Equal(t, int64(2), getIntFromStore(store, anteKey))
  1026  	require.Equal(t, int64(1), getIntFromStore(store, deliverKey))
  1027  
  1028  	// commit
  1029  	app.EndBlock(abci.RequestEndBlock{})
  1030  	app.Commit()
  1031  }
  1032  
  1033  func TestGasConsumptionBadTx(t *testing.T) {
  1034  	t.Parallel()
  1035  
  1036  	gasWanted := int64(5)
  1037  	anteOpt := func(bapp *BaseApp) {
  1038  		bapp.SetAnteHandler(func(ctx Context, tx Tx, simulate bool) (newCtx Context, res Result, abort bool) {
  1039  			gmeter := store.NewPassthroughGasMeter(
  1040  				ctx.GasMeter(),
  1041  				gasWanted,
  1042  			)
  1043  			newCtx = ctx.WithGasMeter(gmeter)
  1044  
  1045  			newCtx.GasMeter().ConsumeGas(getCounter(tx), "counter-ante")
  1046  			if getFailOnAnte(tx) {
  1047  				res.Error = ABCIError(std.ErrInternal("ante handler failure"))
  1048  				return newCtx, res, true
  1049  			}
  1050  
  1051  			res = Result{
  1052  				GasWanted: gasWanted,
  1053  			}
  1054  			return
  1055  		})
  1056  	}
  1057  
  1058  	routerOpt := func(bapp *BaseApp) {
  1059  		bapp.Router().AddRoute(routeMsgCounter, newTestHandler(func(ctx Context, msg Msg) Result {
  1060  			count := msg.(msgCounter).Counter
  1061  			ctx.GasMeter().ConsumeGas(count, "counter-handler")
  1062  			return Result{}
  1063  		}))
  1064  	}
  1065  
  1066  	app := setupBaseApp(t, anteOpt, routerOpt)
  1067  	app.InitChain(abci.RequestInitChain{
  1068  		ChainID: "test-chain",
  1069  		ConsensusParams: &abci.ConsensusParams{
  1070  			Block: &abci.BlockParams{
  1071  				MaxGas: 9,
  1072  			},
  1073  		},
  1074  	})
  1075  	// app.InitChain(abci.RequestInitChain{ChainID: "test-chain"})
  1076  
  1077  	header := &bft.Header{ChainID: "test-chain", Height: app.LastBlockHeight() + 1}
  1078  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
  1079  
  1080  	tx := newTxCounter(5, 0)
  1081  	setFailOnAnte(&tx, true)
  1082  	txBytes, err := amino.Marshal(tx)
  1083  	require.NoError(t, err)
  1084  
  1085  	res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
  1086  	require.False(t, res.IsOK(), fmt.Sprintf("%v", res))
  1087  
  1088  	// require next tx to fail due to black gas limit
  1089  	tx = newTxCounter(5, 0)
  1090  	txBytes, err = amino.Marshal(tx)
  1091  	require.NoError(t, err)
  1092  
  1093  	res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
  1094  	require.False(t, res.IsOK(), fmt.Sprintf("%v", res))
  1095  }
  1096  
  1097  // Test that we can only query from the latest committed state.
  1098  func TestQuery(t *testing.T) {
  1099  	t.Parallel()
  1100  
  1101  	key, value := []byte("hello"), []byte("goodbye")
  1102  	anteOpt := func(bapp *BaseApp) {
  1103  		bapp.SetAnteHandler(func(ctx Context, tx Tx, simulate bool) (newCtx Context, res Result, abort bool) {
  1104  			newCtx = ctx
  1105  			store := ctx.Store(mainKey)
  1106  			store.Set(key, value)
  1107  			return
  1108  		})
  1109  	}
  1110  
  1111  	routerOpt := func(bapp *BaseApp) {
  1112  		bapp.Router().AddRoute(routeMsgCounter, newTestHandler(func(ctx Context, msg Msg) Result {
  1113  			store := ctx.Store(mainKey)
  1114  			store.Set(key, value)
  1115  			return Result{}
  1116  		}))
  1117  	}
  1118  
  1119  	app := setupBaseApp(t, anteOpt, routerOpt)
  1120  
  1121  	app.InitChain(abci.RequestInitChain{ChainID: "test-chain"})
  1122  
  1123  	// NOTE: "/store/main" tells us Store
  1124  	// and the final "/key" says to use the data as the
  1125  	// key in the given Store ...
  1126  	query := abci.RequestQuery{
  1127  		Path: ".store/main/key",
  1128  		Data: key,
  1129  	}
  1130  	tx := newTxCounter(0, 0)
  1131  
  1132  	// query is empty before we do anything
  1133  	res := app.Query(query)
  1134  	require.Equal(t, 0, len(res.Value))
  1135  
  1136  	// query is still empty after a CheckTx
  1137  	resTx := app.Check(tx)
  1138  	require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx))
  1139  	res = app.Query(query)
  1140  	require.Equal(t, 0, len(res.Value))
  1141  
  1142  	// query is still empty after a DeliverTx before we commit
  1143  	header := &bft.Header{ChainID: "test-chain", Height: app.LastBlockHeight() + 1}
  1144  	app.BeginBlock(abci.RequestBeginBlock{Header: header})
  1145  
  1146  	resTx = app.Deliver(tx)
  1147  	require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx))
  1148  	res = app.Query(query)
  1149  	require.Equal(t, 0, len(res.Value))
  1150  
  1151  	// query returns correct value after Commit
  1152  	app.Commit()
  1153  	res = app.Query(query)
  1154  	require.Equal(t, value, res.Value)
  1155  }
  1156  
  1157  func TestGetMaximumBlockGas(t *testing.T) {
  1158  	app := setupBaseApp(t)
  1159  
  1160  	app.setConsensusParams(&abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: 0}})
  1161  	require.Equal(t, int64(0), app.getMaximumBlockGas())
  1162  
  1163  	app.setConsensusParams(&abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: -1}})
  1164  	require.Equal(t, int64(0), app.getMaximumBlockGas())
  1165  
  1166  	app.setConsensusParams(&abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: 5000000}})
  1167  	require.Equal(t, int64(5000000), app.getMaximumBlockGas())
  1168  
  1169  	app.setConsensusParams(&abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: -5000000}})
  1170  	require.Panics(t, func() { app.getMaximumBlockGas() })
  1171  }