github.com/Finschia/finschia-sdk@v0.48.1/baseapp/baseapp.go (about)

     1  package baseapp
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"strings"
     8  	"sync"
     9  
    10  	"github.com/gogo/protobuf/proto"
    11  
    12  	abci "github.com/tendermint/tendermint/abci/types"
    13  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    14  
    15  	ocabci "github.com/Finschia/ostracon/abci/types"
    16  	"github.com/Finschia/ostracon/crypto/tmhash"
    17  	"github.com/Finschia/ostracon/libs/log"
    18  	dbm "github.com/tendermint/tm-db"
    19  
    20  	"github.com/Finschia/finschia-sdk/codec/types"
    21  	"github.com/Finschia/finschia-sdk/server/config"
    22  	"github.com/Finschia/finschia-sdk/snapshots"
    23  	"github.com/Finschia/finschia-sdk/store"
    24  	"github.com/Finschia/finschia-sdk/store/rootmulti"
    25  	sdk "github.com/Finschia/finschia-sdk/types"
    26  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
    27  	"github.com/Finschia/finschia-sdk/x/auth/legacy/legacytx"
    28  )
    29  
    30  var _ ocabci.Application = (*BaseApp)(nil)
    31  
    32  type (
    33  	// StoreLoader defines a customizable function to control how we load the CommitMultiStore
    34  	// from disk. This is useful for state migration, when loading a datastore written with
    35  	// an older version of the software. In particular, if a module changed the substore key name
    36  	// (or removed a substore) between two versions of the software.
    37  	StoreLoader func(ms sdk.CommitMultiStore) error
    38  )
    39  
    40  // BaseApp reflects the ABCI application implementation.
    41  type BaseApp struct { //nolint: maligned
    42  	// initialized on creation
    43  	logger            log.Logger
    44  	name              string // application name from abci.Info
    45  	interfaceRegistry types.InterfaceRegistry
    46  	txDecoder         sdk.TxDecoder // unmarshal []byte into sdk.Tx
    47  
    48  	anteHandler sdk.AnteHandler // ante handler for fee and auth
    49  
    50  	appStore
    51  	baseappVersions
    52  	peerFilters
    53  	snapshotData
    54  	abciData
    55  	moduleRouter
    56  
    57  	// volatile states:
    58  	//
    59  	// checkState is set on InitChain and reset on Commit
    60  	// deliverState is set on InitChain and BeginBlock and set to nil on Commit
    61  	checkState   *state // for CheckTx
    62  	deliverState *state // for DeliverTx
    63  
    64  	checkStateMtx sync.RWMutex
    65  
    66  	checkAccountWGs *AccountWGs
    67  	chCheckTx       chan *RequestCheckTxAsync
    68  	chCheckTxSize   uint // chCheckTxSize is the initial size for chCheckTx
    69  
    70  	// paramStore is used to query for ABCI consensus parameters from an
    71  	// application parameter store.
    72  	paramStore ParamStore
    73  
    74  	// The minimum gas prices a validator is willing to accept for processing a
    75  	// transaction. This is mainly used for DoS and spam prevention.
    76  	minGasPrices sdk.DecCoins
    77  
    78  	// initialHeight is the initial height at which we start the baseapp
    79  	initialHeight int64
    80  
    81  	// flag for sealing options and parameters to a BaseApp
    82  	sealed bool
    83  
    84  	// block height at which to halt the chain and gracefully shutdown
    85  	haltHeight uint64
    86  
    87  	// minimum block time (in Unix seconds) at which to halt the chain and gracefully shutdown
    88  	haltTime uint64
    89  
    90  	// minRetainBlocks defines the minimum block height offset from the current
    91  	// block being committed, such that all blocks past this offset are pruned
    92  	// from Tendermint. It is used as part of the process of determining the
    93  	// ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 indicates
    94  	// that no blocks should be pruned.
    95  	//
    96  	// Note: Tendermint block pruning is dependant on this parameter in conunction
    97  	// with the unbonding (safety threshold) period, state pruning and state sync
    98  	// snapshot parameters to determine the correct minimum value of
    99  	// ResponseCommit.RetainHeight.
   100  	minRetainBlocks uint64
   101  
   102  	// recovery handler for app.runTx method
   103  	runTxRecoveryMiddleware recoveryMiddleware
   104  
   105  	// trace set will return full stack traces for errors in ABCI Log field
   106  	trace bool
   107  
   108  	// indexEvents defines the set of events in the form {eventType}.{attributeKey},
   109  	// which informs Tendermint what to index. If empty, all events will be indexed.
   110  	indexEvents map[string]struct{}
   111  
   112  	// abciListeners for hooking into the ABCI message processing of the BaseApp
   113  	// and exposing the requests and responses to external consumers
   114  	abciListeners []ABCIListener
   115  }
   116  
   117  type appStore struct {
   118  	db          dbm.DB               // common DB backend
   119  	cms         sdk.CommitMultiStore // Main (uncached) state
   120  	storeLoader StoreLoader          // function to handle store loading, may be overridden with SetStoreLoader()
   121  
   122  	// an inter-block write-through cache provided to the context during deliverState
   123  	interBlockCache sdk.MultiStorePersistentCache
   124  
   125  	fauxMerkleMode bool // if true, IAVL MountStores uses MountStoresDB for simulation speed.
   126  }
   127  
   128  type moduleRouter struct {
   129  	router           sdk.Router        // handle any kind of message
   130  	queryRouter      sdk.QueryRouter   // router for redirecting query calls
   131  	grpcQueryRouter  *GRPCQueryRouter  // router for redirecting gRPC query calls
   132  	msgServiceRouter *MsgServiceRouter // router for redirecting Msg service messages
   133  }
   134  
   135  type abciData struct {
   136  	initChainer  sdk.InitChainer  // initialize state with validators and state blob
   137  	beginBlocker sdk.BeginBlocker // logic to run before any txs
   138  	endBlocker   sdk.EndBlocker   // logic to run after all txs, and to determine valset changes
   139  
   140  	// absent validators from begin block
   141  	voteInfos []abci.VoteInfo
   142  }
   143  
   144  type baseappVersions struct {
   145  	// application's version string
   146  	version string
   147  
   148  	// application's protocol version that increments on every upgrade
   149  	// if BaseApp is passed to the upgrade keeper's NewKeeper method.
   150  	appVersion uint64
   151  }
   152  
   153  // should really get handled in some db struct
   154  // which then has a sub-item, persistence fields
   155  type snapshotData struct {
   156  	// manages snapshots, i.e. dumps of app state at certain intervals
   157  	snapshotManager    *snapshots.Manager
   158  	snapshotInterval   uint64 // block interval between state sync snapshots
   159  	snapshotKeepRecent uint32 // recent state sync snapshots to keep
   160  }
   161  
   162  // NewBaseApp returns a reference to an initialized BaseApp. It accepts a
   163  // variadic number of option functions, which act on the BaseApp to set
   164  // configuration choices.
   165  //
   166  // NOTE: The db is used to store the version number for now.
   167  func NewBaseApp(
   168  	name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp),
   169  ) *BaseApp {
   170  	app := &BaseApp{
   171  		logger: logger,
   172  		name:   name,
   173  		appStore: appStore{
   174  			db:             db,
   175  			cms:            store.NewCommitMultiStore(db),
   176  			storeLoader:    DefaultStoreLoader,
   177  			fauxMerkleMode: false,
   178  		},
   179  		moduleRouter: moduleRouter{
   180  			router:           NewRouter(),
   181  			queryRouter:      NewQueryRouter(),
   182  			grpcQueryRouter:  NewGRPCQueryRouter(),
   183  			msgServiceRouter: NewMsgServiceRouter(),
   184  		},
   185  		txDecoder:       txDecoder,
   186  		checkAccountWGs: NewAccountWGs(),
   187  	}
   188  
   189  	for _, option := range options {
   190  		option(app)
   191  	}
   192  
   193  	chCheckTxSize := app.chCheckTxSize
   194  	if chCheckTxSize == 0 {
   195  		chCheckTxSize = config.DefaultChanCheckTxSize
   196  	}
   197  	app.chCheckTx = make(chan *RequestCheckTxAsync, chCheckTxSize)
   198  
   199  	if app.interBlockCache != nil {
   200  		app.cms.SetInterBlockCache(app.interBlockCache)
   201  	}
   202  
   203  	app.runTxRecoveryMiddleware = newDefaultRecoveryMiddleware()
   204  
   205  	app.startReactors()
   206  
   207  	return app
   208  }
   209  
   210  // Name returns the name of the BaseApp.
   211  func (app *BaseApp) Name() string {
   212  	return app.name
   213  }
   214  
   215  // AppVersion returns the application's protocol version.
   216  func (app *BaseApp) AppVersion() uint64 {
   217  	return app.appVersion
   218  }
   219  
   220  // Version returns the application's version string.
   221  func (app *BaseApp) Version() string {
   222  	return app.version
   223  }
   224  
   225  // Logger returns the logger of the BaseApp.
   226  func (app *BaseApp) Logger() log.Logger {
   227  	return app.logger
   228  }
   229  
   230  // Trace returns the boolean value for logging error stack traces.
   231  func (app *BaseApp) Trace() bool {
   232  	return app.trace
   233  }
   234  
   235  // MsgServiceRouter returns the MsgServiceRouter of a BaseApp.
   236  func (app *BaseApp) MsgServiceRouter() *MsgServiceRouter { return app.msgServiceRouter }
   237  
   238  // MountStores mounts all IAVL or DB stores to the provided keys in the BaseApp
   239  // multistore.
   240  func (app *BaseApp) MountStores(keys ...sdk.StoreKey) {
   241  	for _, key := range keys {
   242  		switch key.(type) {
   243  		case *sdk.KVStoreKey:
   244  			if !app.fauxMerkleMode {
   245  				app.MountStore(key, sdk.StoreTypeIAVL)
   246  			} else {
   247  				// StoreTypeDB doesn't do anything upon commit, and it doesn't
   248  				// retain history, but it's useful for faster simulation.
   249  				app.MountStore(key, sdk.StoreTypeDB)
   250  			}
   251  
   252  		default:
   253  			panic("Unrecognized store key type " + reflect.TypeOf(key).Name())
   254  		}
   255  	}
   256  }
   257  
   258  // MountKVStores mounts all IAVL or DB stores to the provided keys in the
   259  // BaseApp multistore.
   260  func (app *BaseApp) MountKVStores(keys map[string]*sdk.KVStoreKey) {
   261  	for _, key := range keys {
   262  		if !app.fauxMerkleMode {
   263  			app.MountStore(key, sdk.StoreTypeIAVL)
   264  		} else {
   265  			// StoreTypeDB doesn't do anything upon commit, and it doesn't
   266  			// retain history, but it's useful for faster simulation.
   267  			app.MountStore(key, sdk.StoreTypeDB)
   268  		}
   269  	}
   270  }
   271  
   272  // MountMemoryStores mounts all in-memory KVStores with the BaseApp's internal
   273  // commit multi-store.
   274  func (app *BaseApp) MountMemoryStores(keys map[string]*sdk.MemoryStoreKey) {
   275  	for _, memKey := range keys {
   276  		app.MountStore(memKey, sdk.StoreTypeMemory)
   277  	}
   278  }
   279  
   280  // MountStore mounts a store to the provided key in the BaseApp multistore,
   281  // using the default DB.
   282  func (app *BaseApp) MountStore(key sdk.StoreKey, typ sdk.StoreType) {
   283  	app.cms.MountStoreWithDB(key, typ, nil)
   284  }
   285  
   286  // LoadLatestVersion loads the latest application version. It will panic if
   287  // called more than once on a running BaseApp.
   288  func (app *BaseApp) LoadLatestVersion() error {
   289  	err := app.storeLoader(app.cms)
   290  	if err != nil {
   291  		return fmt.Errorf("failed to load latest version: %w", err)
   292  	}
   293  
   294  	return app.init()
   295  }
   296  
   297  // DefaultStoreLoader will be used by default and loads the latest version
   298  func DefaultStoreLoader(ms sdk.CommitMultiStore) error {
   299  	return ms.LoadLatestVersion()
   300  }
   301  
   302  // CommitMultiStore returns the root multi-store.
   303  // App constructor can use this to access the `cms`.
   304  // UNSAFE: must not be used during the abci life cycle.
   305  func (app *BaseApp) CommitMultiStore() sdk.CommitMultiStore {
   306  	return app.cms
   307  }
   308  
   309  // SnapshotManager returns the snapshot manager.
   310  // application use this to register extra extension snapshotters.
   311  func (app *BaseApp) SnapshotManager() *snapshots.Manager {
   312  	return app.snapshotManager
   313  }
   314  
   315  // LoadVersion loads the BaseApp application version. It will panic if called
   316  // more than once on a running baseapp.
   317  func (app *BaseApp) LoadVersion(version int64) error {
   318  	err := app.cms.LoadVersion(version)
   319  	if err != nil {
   320  		return fmt.Errorf("failed to load version %d: %w", version, err)
   321  	}
   322  
   323  	return app.init()
   324  }
   325  
   326  // LastCommitID returns the last CommitID of the multistore.
   327  func (app *BaseApp) LastCommitID() sdk.CommitID {
   328  	return app.cms.LastCommitID()
   329  }
   330  
   331  // LastBlockHeight returns the last committed block height.
   332  func (app *BaseApp) LastBlockHeight() int64 {
   333  	return app.cms.LastCommitID().Version
   334  }
   335  
   336  func (app *BaseApp) init() error {
   337  	if app.sealed {
   338  		panic("cannot call initFromMainStore: baseapp already sealed")
   339  	}
   340  
   341  	// needed for the export command which inits from store but never calls initchain
   342  	app.setCheckState(tmproto.Header{})
   343  	app.Seal()
   344  
   345  	// make sure the snapshot interval is a multiple of the pruning KeepEvery interval
   346  	if app.snapshotManager != nil && app.snapshotInterval > 0 {
   347  		rms, ok := app.cms.(*rootmulti.Store)
   348  		if !ok {
   349  			return errors.New("state sync snapshots require a rootmulti store")
   350  		}
   351  		pruningOpts := rms.GetPruning()
   352  		if pruningOpts.KeepEvery > 0 && app.snapshotInterval%pruningOpts.KeepEvery != 0 {
   353  			return fmt.Errorf(
   354  				"state sync snapshot interval %v must be a multiple of pruning keep every interval %v",
   355  				app.snapshotInterval, pruningOpts.KeepEvery)
   356  		}
   357  	}
   358  
   359  	return nil
   360  }
   361  
   362  func (app *BaseApp) setMinGasPrices(gasPrices sdk.DecCoins) {
   363  	app.minGasPrices = gasPrices
   364  }
   365  
   366  func (app *BaseApp) setHaltHeight(haltHeight uint64) {
   367  	app.haltHeight = haltHeight
   368  }
   369  
   370  func (app *BaseApp) setHaltTime(haltTime uint64) {
   371  	app.haltTime = haltTime
   372  }
   373  
   374  func (app *BaseApp) setMinRetainBlocks(minRetainBlocks uint64) {
   375  	app.minRetainBlocks = minRetainBlocks
   376  }
   377  
   378  func (app *BaseApp) setInterBlockCache(cache sdk.MultiStorePersistentCache) {
   379  	app.interBlockCache = cache
   380  }
   381  
   382  func (app *BaseApp) setTrace(trace bool) {
   383  	app.trace = trace
   384  }
   385  
   386  func (app *BaseApp) setIndexEvents(ie []string) {
   387  	app.indexEvents = make(map[string]struct{})
   388  
   389  	for _, e := range ie {
   390  		app.indexEvents[e] = struct{}{}
   391  	}
   392  }
   393  
   394  // Router returns the router of the BaseApp.
   395  func (app *BaseApp) Router() sdk.Router {
   396  	if app.sealed {
   397  		// We cannot return a Router when the app is sealed because we can't have
   398  		// any routes modified which would cause unexpected routing behavior.
   399  		panic("Router() on sealed BaseApp")
   400  	}
   401  
   402  	return app.router
   403  }
   404  
   405  // QueryRouter returns the QueryRouter of a BaseApp.
   406  func (app *BaseApp) QueryRouter() sdk.QueryRouter { return app.queryRouter }
   407  
   408  // Seal seals a BaseApp. It prohibits any further modifications to a BaseApp.
   409  func (app *BaseApp) Seal() { app.sealed = true }
   410  
   411  // IsSealed returns true if the BaseApp is sealed and false otherwise.
   412  func (app *BaseApp) IsSealed() bool { return app.sealed }
   413  
   414  // setCheckState sets the BaseApp's checkState with a branched multi-store
   415  // (i.e. a CacheMultiStore) and a new Context with the same multi-store branch,
   416  // provided header, and minimum gas prices set. It is set on InitChain and reset
   417  // on Commit.
   418  func (app *BaseApp) setCheckState(header tmproto.Header) {
   419  	ms := app.cms.CacheMultiStore()
   420  	app.checkStateMtx.Lock()
   421  	defer app.checkStateMtx.Unlock()
   422  
   423  	ctx := sdk.NewContext(ms, header, true, app.logger).
   424  		WithMinGasPrices(app.minGasPrices).
   425  		WithVoteInfos(app.voteInfos)
   426  
   427  	app.checkState = &state{
   428  		ms:  ms,
   429  		ctx: ctx,
   430  	}
   431  }
   432  
   433  // setDeliverState sets the BaseApp's deliverState with a branched multi-store
   434  // (i.e. a CacheMultiStore) and a new Context with the same multi-store branch,
   435  // and provided header. It is set on InitChain and BeginBlock and set to nil on
   436  // Commit.
   437  func (app *BaseApp) setDeliverState(header tmproto.Header) {
   438  	ms := app.cms.CacheMultiStore()
   439  	app.deliverState = &state{
   440  		ms:  ms,
   441  		ctx: sdk.NewContext(ms, header, false, app.logger),
   442  	}
   443  }
   444  
   445  // GetConsensusParams returns the current consensus parameters from the BaseApp's
   446  // ParamStore. If the BaseApp has no ParamStore defined, nil is returned.
   447  func (app *BaseApp) GetConsensusParams(ctx sdk.Context) *abci.ConsensusParams {
   448  	if app.paramStore == nil {
   449  		return nil
   450  	}
   451  
   452  	cp := new(abci.ConsensusParams)
   453  
   454  	if app.paramStore.Has(ctx, ParamStoreKeyBlockParams) {
   455  		var bp abci.BlockParams
   456  
   457  		app.paramStore.Get(ctx, ParamStoreKeyBlockParams, &bp)
   458  		cp.Block = &bp
   459  	}
   460  
   461  	if app.paramStore.Has(ctx, ParamStoreKeyEvidenceParams) {
   462  		var ep tmproto.EvidenceParams
   463  
   464  		app.paramStore.Get(ctx, ParamStoreKeyEvidenceParams, &ep)
   465  		cp.Evidence = &ep
   466  	}
   467  
   468  	if app.paramStore.Has(ctx, ParamStoreKeyValidatorParams) {
   469  		var vp tmproto.ValidatorParams
   470  
   471  		app.paramStore.Get(ctx, ParamStoreKeyValidatorParams, &vp)
   472  		cp.Validator = &vp
   473  	}
   474  
   475  	return cp
   476  }
   477  
   478  // AddRunTxRecoveryHandler adds custom app.runTx method panic handlers.
   479  func (app *BaseApp) AddRunTxRecoveryHandler(handlers ...RecoveryHandler) {
   480  	for _, h := range handlers {
   481  		app.runTxRecoveryMiddleware = newRecoveryMiddleware(h, app.runTxRecoveryMiddleware)
   482  	}
   483  }
   484  
   485  // StoreConsensusParams sets the consensus parameters to the baseapp's param store.
   486  func (app *BaseApp) StoreConsensusParams(ctx sdk.Context, cp *abci.ConsensusParams) {
   487  	if app.paramStore == nil {
   488  		panic("cannot store consensus params with no params store set")
   489  	}
   490  
   491  	if cp == nil {
   492  		return
   493  	}
   494  
   495  	app.paramStore.Set(ctx, ParamStoreKeyBlockParams, cp.Block)
   496  	app.paramStore.Set(ctx, ParamStoreKeyEvidenceParams, cp.Evidence)
   497  	app.paramStore.Set(ctx, ParamStoreKeyValidatorParams, cp.Validator)
   498  }
   499  
   500  // getMaximumBlockGas gets the maximum gas from the consensus params. It panics
   501  // if maximum block gas is less than negative one and returns zero if negative
   502  // one.
   503  func (app *BaseApp) getMaximumBlockGas(ctx sdk.Context) uint64 {
   504  	cp := app.GetConsensusParams(ctx)
   505  	if cp == nil || cp.Block == nil {
   506  		return 0
   507  	}
   508  
   509  	maxGas := cp.Block.MaxGas
   510  
   511  	switch {
   512  	case maxGas < -1:
   513  		panic(fmt.Sprintf("invalid maximum block gas: %d", maxGas))
   514  
   515  	case maxGas == -1:
   516  		return 0
   517  
   518  	default:
   519  		return uint64(maxGas)
   520  	}
   521  }
   522  
   523  func (app *BaseApp) validateHeight(req ocabci.RequestBeginBlock) error {
   524  	if req.Header.Height < 1 {
   525  		return fmt.Errorf("invalid height: %d", req.Header.Height)
   526  	}
   527  
   528  	// expectedHeight holds the expected height to validate.
   529  	var expectedHeight int64
   530  	if app.LastBlockHeight() == 0 && app.initialHeight > 1 {
   531  		// In this case, we're validating the first block of the chain (no
   532  		// previous commit). The height we're expecting is the initial height.
   533  		expectedHeight = app.initialHeight
   534  	} else {
   535  		// This case can means two things:
   536  		// - either there was already a previous commit in the store, in which
   537  		// case we increment the version from there,
   538  		// - or there was no previous commit, and initial version was not set,
   539  		// in which case we start at version 1.
   540  		expectedHeight = app.LastBlockHeight() + 1
   541  	}
   542  
   543  	if req.Header.Height != expectedHeight {
   544  		return fmt.Errorf("invalid height: %d; expected: %d", req.Header.Height, expectedHeight)
   545  	}
   546  
   547  	return nil
   548  }
   549  
   550  // validateBasicTxMsgs executes basic validator calls for messages.
   551  func validateBasicTxMsgs(msgs []sdk.Msg) error {
   552  	if len(msgs) == 0 {
   553  		return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "must contain at least one message")
   554  	}
   555  
   556  	for _, msg := range msgs {
   557  		err := msg.ValidateBasic()
   558  		if err != nil {
   559  			return err
   560  		}
   561  	}
   562  
   563  	return nil
   564  }
   565  
   566  func (app *BaseApp) getCheckContextForTx(txBytes []byte, recheck bool) sdk.Context {
   567  	app.checkStateMtx.RLock()
   568  	defer app.checkStateMtx.RUnlock()
   569  	return app.getContextForTx(app.checkState, txBytes).WithIsReCheckTx(recheck)
   570  }
   571  
   572  // retrieve the context for the tx w/ txBytes and other memoized values.
   573  func (app *BaseApp) getRunContextForTx(txBytes []byte, simulate bool) sdk.Context {
   574  	if !simulate {
   575  		return app.getContextForTx(app.deliverState, txBytes)
   576  	}
   577  
   578  	app.checkStateMtx.RLock()
   579  	defer app.checkStateMtx.RUnlock()
   580  	ctx := app.getContextForTx(app.checkState, txBytes)
   581  	ctx, _ = ctx.CacheContext()
   582  	return ctx
   583  }
   584  
   585  func (app *BaseApp) getContextForTx(s *state, txBytes []byte) sdk.Context {
   586  	ctx := s.ctx.WithTxBytes(txBytes)
   587  	ctx = ctx.WithConsensusParams(app.GetConsensusParams(ctx))
   588  	return ctx
   589  }
   590  
   591  // cacheTxContext returns a new context based off of the provided context with
   592  // a branched multi-store.
   593  func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context, sdk.CacheMultiStore) {
   594  	ms := ctx.MultiStore()
   595  	// TODO: https://github.com/cosmos/cosmos-sdk/issues/2824
   596  	msCache := ms.CacheMultiStore()
   597  	if msCache.TracingEnabled() {
   598  		msCache = msCache.SetTracingContext(
   599  			sdk.TraceContext(
   600  				map[string]interface{}{
   601  					"txHash": fmt.Sprintf("%X", tmhash.Sum(txBytes)),
   602  				},
   603  			),
   604  		).(sdk.CacheMultiStore)
   605  	}
   606  
   607  	return ctx.WithMultiStore(msCache), msCache
   608  }
   609  
   610  // stateless checkTx
   611  func (app *BaseApp) preCheckTx(txBytes []byte) (tx sdk.Tx, err error) {
   612  	defer func() {
   613  		if r := recover(); r != nil {
   614  			recoveryMW := newDefaultRecoveryMiddleware()
   615  			err = processRecovery(r, recoveryMW)
   616  		}
   617  	}()
   618  
   619  	tx, err = app.txDecoder(txBytes)
   620  	if err != nil {
   621  		return tx, err
   622  	}
   623  
   624  	msgs := tx.GetMsgs()
   625  	err = validateBasicTxMsgs(msgs)
   626  
   627  	return tx, err
   628  }
   629  
   630  func (app *BaseApp) PreCheckTx(txBytes []byte) (sdk.Tx, error) {
   631  	return app.preCheckTx(txBytes)
   632  }
   633  
   634  func (app *BaseApp) checkTx(txBytes []byte, tx sdk.Tx, recheck bool) (gInfo sdk.GasInfo, err error) {
   635  	ctx := app.getCheckContextForTx(txBytes, recheck)
   636  	gasCtx := &ctx
   637  
   638  	defer func() {
   639  		if r := recover(); r != nil {
   640  			recoveryMW := newDefaultRecoveryMiddleware()
   641  			err = processRecovery(r, recoveryMW)
   642  		}
   643  		gInfo = sdk.GasInfo{GasWanted: gasCtx.GasMeter().Limit(), GasUsed: gasCtx.GasMeter().GasConsumed()}
   644  	}()
   645  
   646  	var anteCtx sdk.Context
   647  	anteCtx, err = app.anteTx(ctx, txBytes, tx, false)
   648  	if !anteCtx.IsZero() {
   649  		gasCtx = &anteCtx
   650  	}
   651  
   652  	return gInfo, err
   653  }
   654  
   655  func (app *BaseApp) anteTx(ctx sdk.Context, txBytes []byte, tx sdk.Tx, simulate bool) (sdk.Context, error) {
   656  	if app.anteHandler == nil {
   657  		return ctx, nil
   658  	}
   659  
   660  	// Branch context before AnteHandler call in case it aborts.
   661  	// This is required for both CheckTx and DeliverTx.
   662  	// Ref: https://github.com/cosmos/cosmos-sdk/issues/2772
   663  	//
   664  	// NOTE: Alternatively, we could require that AnteHandler ensures that
   665  	// writes do not happen if aborted/failed.  This may have some
   666  	// performance benefits, but it'll be more difficult to get right.
   667  	anteCtx, msCache := app.cacheTxContext(ctx, txBytes)
   668  	anteCtx = anteCtx.WithEventManager(sdk.NewEventManager())
   669  	newCtx, err := app.anteHandler(anteCtx, tx, simulate)
   670  
   671  	if err != nil {
   672  		return newCtx, err
   673  	}
   674  
   675  	msCache.Write()
   676  	return newCtx, err
   677  }
   678  
   679  // runTx processes a transaction within a given execution mode, encoded transaction
   680  // bytes, and the decoded transaction itself. All state transitions occur through
   681  // a cached Context depending on the mode provided. State only gets persisted
   682  // if all messages get executed successfully and the execution mode is DeliverTx.
   683  // Note, gas execution info is always returned. A reference to a Result is
   684  // returned if the tx does not run out of gas and if all the messages are valid
   685  // and execute successfully. An error is returned otherwise.
   686  func (app *BaseApp) runTx(txBytes []byte, tx sdk.Tx, simulate bool) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) {
   687  	ctx := app.getRunContextForTx(txBytes, simulate)
   688  	ms := ctx.MultiStore()
   689  
   690  	// only run the tx if there is block gas remaining
   691  	if !simulate && ctx.BlockGasMeter().IsOutOfGas() {
   692  		return gInfo, nil, nil, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx")
   693  	}
   694  
   695  	defer func() {
   696  		if r := recover(); r != nil {
   697  			recoveryMW := newOutOfGasRecoveryMiddleware(ctx.GasMeter().Limit(), ctx, app.runTxRecoveryMiddleware)
   698  			err, result = processRecovery(r, recoveryMW), nil
   699  		}
   700  
   701  		gInfo = sdk.GasInfo{GasWanted: ctx.GasMeter().Limit(), GasUsed: ctx.GasMeter().GasConsumed()}
   702  	}()
   703  
   704  	blockGasConsumed := false
   705  	// consumeBlockGas makes sure block gas is consumed at most once. It must happen after
   706  	// tx processing, and must be execute even if tx processing fails. Hence we use trick with `defer`
   707  	consumeBlockGas := func() {
   708  		if !blockGasConsumed {
   709  			blockGasConsumed = true
   710  			ctx.BlockGasMeter().ConsumeGas(
   711  				ctx.GasMeter().GasConsumedToLimit(), "block gas meter",
   712  			)
   713  		}
   714  	}
   715  
   716  	// If BlockGasMeter() panics it will be caught by the above recover and will
   717  	// return an error - in any case BlockGasMeter will consume gas past the limit.
   718  	//
   719  	// NOTE: This must exist in a separate defer function for the above recovery
   720  	// to recover from this one.
   721  	if !simulate {
   722  		defer consumeBlockGas()
   723  	}
   724  
   725  	msgs := tx.GetMsgs()
   726  	if err = validateBasicTxMsgs(msgs); err != nil {
   727  		return sdk.GasInfo{}, nil, nil, err
   728  	}
   729  
   730  	var newCtx sdk.Context
   731  	newCtx, err = app.anteTx(ctx, txBytes, tx, simulate)
   732  	if !newCtx.IsZero() {
   733  		// At this point, newCtx.MultiStore() is a store branch, or something else
   734  		// replaced by the AnteHandler. We want the original multistore.
   735  		//
   736  		// Also, in the case of the tx aborting, we need to track gas consumed via
   737  		// the instantiated gas meter in the AnteHandler, so we update the context
   738  		// prior to returning.
   739  		ctx = newCtx.WithMultiStore(ms)
   740  	}
   741  
   742  	if err != nil {
   743  		return gInfo, nil, nil, err
   744  	}
   745  
   746  	events := ctx.EventManager().Events()
   747  	anteEvents = events.ToABCIEvents()
   748  
   749  	// Create a new Context based off of the existing Context with a MultiStore branch
   750  	// in case message processing fails. At this point, the MultiStore
   751  	// is a branch of a branch.
   752  	runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes)
   753  
   754  	// Attempt to execute all messages and only update state if all messages pass
   755  	// and we're in DeliverTx. Note, runMsgs will never return a reference to a
   756  	// Result if any single message fails or does not have a registered Handler.
   757  	result, err = app.runMsgs(runMsgCtx, msgs)
   758  	if err == nil && !simulate {
   759  		// When block gas exceeds, it'll panic and won't commit the cached store.
   760  		consumeBlockGas()
   761  
   762  		msCache.Write()
   763  
   764  		if len(anteEvents) > 0 {
   765  			// append the events in the order of occurrence
   766  			result.Events = append(anteEvents, result.Events...)
   767  		}
   768  	}
   769  
   770  	return gInfo, result, anteEvents, err
   771  }
   772  
   773  // runMsgs iterates through a list of messages and executes them with the provided
   774  // Context and execution mode. Messages will only be executed during simulation
   775  // and DeliverTx. An error is returned if any single message fails or if a
   776  // Handler does not exist for a given message route. Otherwise, a reference to a
   777  // Result is returned. The caller must not commit state if an error is returned.
   778  func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg) (*sdk.Result, error) {
   779  	msgLogs := make(sdk.ABCIMessageLogs, 0, len(msgs))
   780  	events := sdk.EmptyEvents()
   781  	txMsgData := &sdk.TxMsgData{
   782  		Data: make([]*sdk.MsgData, 0, len(msgs)),
   783  	}
   784  
   785  	// NOTE: GasWanted is determined by the AnteHandler and GasUsed by the GasMeter.
   786  	for i, msg := range msgs {
   787  		var (
   788  			msgResult *sdk.Result
   789  			err       error
   790  		)
   791  
   792  		if handler := app.msgServiceRouter.Handler(msg); handler != nil {
   793  			// ADR 031 request type routing
   794  			msgResult, err = handler(ctx, msg)
   795  		} else if legacyMsg, ok := msg.(legacytx.LegacyMsg); ok {
   796  			// legacy sdk.Msg routing
   797  			// Assuming that the app developer has migrated all their Msgs to
   798  			// proto messages and has registered all `Msg services`, then this
   799  			// path should never be called, because all those Msgs should be
   800  			// registered within the `msgServiceRouter` already.
   801  			msgRoute := legacyMsg.Route()
   802  			handler := app.router.Route(ctx, msgRoute)
   803  			if handler == nil {
   804  				return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s; message index: %d", msgRoute, i)
   805  			}
   806  
   807  			msgResult, err = handler(ctx, msg)
   808  		} else {
   809  			return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "can't route message %+v", msg)
   810  		}
   811  
   812  		if err != nil {
   813  			return nil, sdkerrors.Wrapf(err, "failed to execute message; message index: %d", i)
   814  		}
   815  
   816  		// create message events
   817  		msgEvents := createEvents(msgResult.GetEvents(), msg)
   818  
   819  		// append message events, data and logs
   820  		//
   821  		// Note: Each message result's data must be length-prefixed in order to
   822  		// separate each result.
   823  		events = events.AppendEvents(msgEvents)
   824  
   825  		txMsgData.Data = append(txMsgData.Data, &sdk.MsgData{MsgType: sdk.MsgTypeURL(msg), Data: msgResult.Data})
   826  		msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint32(i), msgResult.Log, msgEvents))
   827  	}
   828  
   829  	data, err := proto.Marshal(txMsgData)
   830  	if err != nil {
   831  		return nil, sdkerrors.Wrap(err, "failed to marshal tx data")
   832  	}
   833  
   834  	return &sdk.Result{
   835  		Data:   data,
   836  		Log:    strings.TrimSpace(msgLogs.String()),
   837  		Events: events.ToABCIEvents(),
   838  	}, nil
   839  }
   840  
   841  func createEvents(events sdk.Events, msg sdk.Msg) sdk.Events {
   842  	eventMsgName := sdk.MsgTypeURL(msg)
   843  	msgEvent := sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, eventMsgName))
   844  
   845  	// we set the signer attribute as the sender
   846  	if len(msg.GetSigners()) > 0 && !msg.GetSigners()[0].Empty() {
   847  		msgEvent = msgEvent.AppendAttributes(sdk.NewAttribute(sdk.AttributeKeySender, msg.GetSigners()[0].String()))
   848  	}
   849  
   850  	// verify that events have no module attribute set
   851  	if _, found := events.GetAttributes(sdk.AttributeKeyModule); !found {
   852  		// here we assume that routes module name is the second element of the route
   853  		// e.g. "/cosmos.bank.v1beta1.MsgSend" => "bank"
   854  		moduleName := strings.Split(eventMsgName, ".")
   855  		if len(moduleName) > 1 {
   856  			// NOTE(0Tech): please remove this condition check after applying ibc-go v7, because it's hard coding for the ibc
   857  			if moduleName[0] != "/ibc" {
   858  				msgEvent = msgEvent.AppendAttributes(sdk.NewAttribute(sdk.AttributeKeyModule, moduleName[1]))
   859  			}
   860  		}
   861  	}
   862  
   863  	return sdk.Events{msgEvent}.AppendEvents(events)
   864  }