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 }