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

     1  package baseapp
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"os"
     9  	"sort"
    10  	"strings"
    11  	"syscall"
    12  	"time"
    13  
    14  	"github.com/gogo/protobuf/proto"
    15  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    16  	"google.golang.org/grpc/codes"
    17  	grpcstatus "google.golang.org/grpc/status"
    18  
    19  	abci "github.com/tendermint/tendermint/abci/types"
    20  
    21  	"github.com/Finschia/finschia-sdk/codec"
    22  	snapshottypes "github.com/Finschia/finschia-sdk/snapshots/types"
    23  	"github.com/Finschia/finschia-sdk/telemetry"
    24  	sdk "github.com/Finschia/finschia-sdk/types"
    25  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
    26  	ocabci "github.com/Finschia/ostracon/abci/types"
    27  )
    28  
    29  // InitChain implements the ABCI interface. It runs the initialization logic
    30  // directly on the CommitMultiStore.
    31  func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitChain) {
    32  	// On a new chain, we consider the init chain block height as 0, even though
    33  	// req.InitialHeight is 1 by default.
    34  	initHeader := tmproto.Header{ChainID: req.ChainId, Time: req.Time}
    35  
    36  	// If req.InitialHeight is > 1, then we set the initial version in the
    37  	// stores.
    38  	if req.InitialHeight > 1 {
    39  		app.initialHeight = req.InitialHeight
    40  		initHeader = tmproto.Header{ChainID: req.ChainId, Height: req.InitialHeight, Time: req.Time}
    41  		err := app.cms.SetInitialVersion(req.InitialHeight)
    42  		if err != nil {
    43  			panic(err)
    44  		}
    45  	}
    46  
    47  	// initialize the deliver state and check state with a correct header
    48  	app.setDeliverState(initHeader)
    49  	app.setCheckState(initHeader)
    50  
    51  	// Store the consensus params in the BaseApp's paramstore. Note, this must be
    52  	// done after the deliver state and context have been set as it's persisted
    53  	// to state.
    54  	if req.ConsensusParams != nil {
    55  		app.StoreConsensusParams(app.deliverState.ctx, req.ConsensusParams)
    56  	}
    57  
    58  	if app.initChainer == nil {
    59  		return
    60  	}
    61  
    62  	// add block gas meter for any genesis transactions (allow infinite gas)
    63  	app.deliverState.ctx = app.deliverState.ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter())
    64  
    65  	res = app.initChainer(app.deliverState.ctx, req)
    66  
    67  	// sanity check
    68  	if len(req.Validators) > 0 {
    69  		if len(req.Validators) != len(res.Validators) {
    70  			panic(
    71  				fmt.Errorf(
    72  					"len(RequestInitChain.Validators) != len(GenesisValidators) (%d != %d)",
    73  					len(req.Validators), len(res.Validators),
    74  				),
    75  			)
    76  		}
    77  
    78  		sort.Sort(abci.ValidatorUpdates(req.Validators))
    79  		sort.Sort(abci.ValidatorUpdates(res.Validators))
    80  
    81  		for i := range res.Validators {
    82  			if !proto.Equal(&res.Validators[i], &req.Validators[i]) {
    83  				panic(fmt.Errorf("genesisValidators[%d] != req.Validators[%d] ", i, i))
    84  			}
    85  		}
    86  	}
    87  
    88  	// In the case of a new chain, AppHash will be the hash of an empty string.
    89  	// During an upgrade, it'll be the hash of the last committed block.
    90  	var appHash []byte
    91  	if !app.LastCommitID().IsZero() {
    92  		appHash = app.LastCommitID().Hash
    93  	} else {
    94  		// $ echo -n '' | sha256sum
    95  		// e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    96  		emptyHash := sha256.Sum256([]byte{})
    97  		appHash = emptyHash[:]
    98  	}
    99  
   100  	// NOTE: We don't commit, but BeginBlock for block `initial_height` starts from this
   101  	// deliverState.
   102  	return abci.ResponseInitChain{
   103  		ConsensusParams: res.ConsensusParams,
   104  		Validators:      res.Validators,
   105  		AppHash:         appHash,
   106  	}
   107  }
   108  
   109  // Info implements the ABCI interface.
   110  func (app *BaseApp) Info(req abci.RequestInfo) abci.ResponseInfo {
   111  	lastCommitID := app.cms.LastCommitID()
   112  
   113  	return abci.ResponseInfo{
   114  		Data:             app.name,
   115  		Version:          app.version,
   116  		AppVersion:       app.appVersion,
   117  		LastBlockHeight:  lastCommitID.Version,
   118  		LastBlockAppHash: lastCommitID.Hash,
   119  	}
   120  }
   121  
   122  // SetOption implements the ABCI interface.
   123  func (app *BaseApp) SetOption(req abci.RequestSetOption) (res abci.ResponseSetOption) {
   124  	return abci.ResponseSetOption{}
   125  }
   126  
   127  // BeginBlock implements the ABCI application interface.
   128  func (app *BaseApp) BeginBlock(req ocabci.RequestBeginBlock) (res abci.ResponseBeginBlock) {
   129  	defer telemetry.MeasureSince(time.Now(), "abci", "begin_block")
   130  
   131  	if app.cms.TracingEnabled() {
   132  		app.cms.SetTracingContext(sdk.TraceContext(
   133  			map[string]interface{}{"blockHeight": req.Header.Height},
   134  		))
   135  	}
   136  
   137  	if err := app.validateHeight(req); err != nil {
   138  		panic(err)
   139  	}
   140  
   141  	// set the signed validators for addition to context in deliverTx
   142  	app.voteInfos = req.LastCommitInfo.GetVotes()
   143  
   144  	// Initialize the DeliverTx state. If this is the first block, it should
   145  	// already be initialized in InitChain. Otherwise app.deliverState will be
   146  	// nil, since it is reset on Commit.
   147  	if app.deliverState == nil {
   148  		app.setDeliverState(req.Header)
   149  	} else {
   150  		// In the first block, app.deliverState.ctx will already be initialized
   151  		// by InitChain. Context is now updated with Header information.
   152  		app.deliverState.ctx = app.deliverState.ctx.
   153  			WithBlockHeader(req.Header).
   154  			WithBlockHeight(req.Header.Height)
   155  	}
   156  
   157  	// add block gas meter
   158  	var gasMeter sdk.GasMeter
   159  	if maxGas := app.getMaximumBlockGas(app.deliverState.ctx); maxGas > 0 {
   160  		gasMeter = sdk.NewGasMeter(maxGas)
   161  	} else {
   162  		gasMeter = sdk.NewInfiniteGasMeter()
   163  	}
   164  
   165  	// NOTE: header hash is not set in NewContext, so we manually set it here
   166  
   167  	app.deliverState.ctx = app.deliverState.ctx.
   168  		WithVoteInfos(app.voteInfos).
   169  		WithBlockGasMeter(gasMeter).
   170  		WithHeaderHash(req.Hash).
   171  		WithConsensusParams(app.GetConsensusParams(app.deliverState.ctx))
   172  
   173  	// we also set block gas meter to checkState in case the application needs to
   174  	// verify gas consumption during (Re)CheckTx
   175  	if app.checkState != nil {
   176  		app.checkState.ctx = app.checkState.ctx.
   177  			WithBlockGasMeter(gasMeter).
   178  			WithHeaderHash(req.Hash)
   179  	}
   180  
   181  	if app.beginBlocker != nil {
   182  		res = app.beginBlocker(app.deliverState.ctx, req)
   183  		res.Events = sdk.MarkEventsToIndex(res.Events, app.indexEvents)
   184  	}
   185  	// set the signed validators for addition to context in deliverTx
   186  	app.voteInfos = req.LastCommitInfo.GetVotes()
   187  
   188  	// call the hooks with the BeginBlock messages
   189  	for _, streamingListener := range app.abciListeners {
   190  		if err := streamingListener.ListenBeginBlock(app.deliverState.ctx, req, res); err != nil {
   191  			app.logger.Error("BeginBlock listening hook failed", "height", req.Header.Height, "err", err)
   192  		}
   193  	}
   194  
   195  	return res
   196  }
   197  
   198  // EndBlock implements the ABCI interface.
   199  func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBlock) {
   200  	defer telemetry.MeasureSince(time.Now(), "abci", "end_block")
   201  
   202  	if app.deliverState.ms.TracingEnabled() {
   203  		app.deliverState.ms = app.deliverState.ms.SetTracingContext(nil).(sdk.CacheMultiStore)
   204  	}
   205  
   206  	if app.endBlocker != nil {
   207  		res = app.endBlocker(app.deliverState.ctx, req)
   208  		res.Events = sdk.MarkEventsToIndex(res.Events, app.indexEvents)
   209  	}
   210  
   211  	if cp := app.GetConsensusParams(app.deliverState.ctx); cp != nil {
   212  		res.ConsensusParamUpdates = cp
   213  	}
   214  
   215  	// call the streaming service hooks with the EndBlock messages
   216  	for _, streamingListener := range app.abciListeners {
   217  		if err := streamingListener.ListenEndBlock(app.deliverState.ctx, req, res); err != nil {
   218  			app.logger.Error("EndBlock listening hook failed", "height", req.Height, "err", err)
   219  		}
   220  	}
   221  
   222  	return res
   223  }
   224  
   225  // CheckTx implements the ABCI interface and executes a tx in CheckTx mode. In
   226  // CheckTx mode, messages are not executed. This means messages are only validated
   227  // and only the AnteHandler is executed. State is persisted to the BaseApp's
   228  // internal CheckTx state if the AnteHandler passes. Otherwise, the ResponseCheckTx
   229  // will contain releveant error information. Regardless of tx execution outcome,
   230  // the ResponseCheckTx will contain relevant gas execution context.
   231  func (app *BaseApp) CheckTxSync(req abci.RequestCheckTx) ocabci.ResponseCheckTx {
   232  	defer telemetry.MeasureSince(time.Now(), "abci", "check_tx")
   233  
   234  	if req.Type != abci.CheckTxType_New && req.Type != abci.CheckTxType_Recheck {
   235  		panic(fmt.Sprintf("unknown RequestCheckTx type: %s", req.Type))
   236  	}
   237  
   238  	tx, err := app.preCheckTx(req.Tx)
   239  	if err != nil {
   240  		return sdkerrors.ResponseCheckTx(err, 0, 0, app.trace)
   241  	}
   242  
   243  	waits, signals := app.checkAccountWGs.Register(tx)
   244  
   245  	app.checkAccountWGs.Wait(waits)
   246  	defer app.checkAccountWGs.Done(signals)
   247  
   248  	gInfo, err := app.checkTx(req.Tx, tx, req.Type == abci.CheckTxType_Recheck)
   249  	if err != nil {
   250  		return sdkerrors.ResponseCheckTx(err, gInfo.GasWanted, gInfo.GasUsed, app.trace)
   251  		// return sdkerrors.ResponseCheckTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, anteEvents, app.trace) // TODO(dudong2): need to fix to use ResponseCheckTxWithEvents
   252  	}
   253  
   254  	return ocabci.ResponseCheckTx{
   255  		GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints?
   256  		GasUsed:   int64(gInfo.GasUsed),   // TODO: Should type accept unsigned ints?
   257  	}
   258  }
   259  
   260  func (app *BaseApp) CheckTxAsync(req abci.RequestCheckTx, callback ocabci.CheckTxCallback) {
   261  	if req.Type != abci.CheckTxType_New && req.Type != abci.CheckTxType_Recheck {
   262  		panic(fmt.Sprintf("unknown RequestCheckTx type: %s", req.Type))
   263  	}
   264  
   265  	reqCheckTx := &RequestCheckTxAsync{
   266  		txBytes:  req.Tx,
   267  		recheck:  req.Type == abci.CheckTxType_Recheck,
   268  		callback: callback,
   269  		prepare:  waitGroup1(),
   270  	}
   271  	app.chCheckTx <- reqCheckTx
   272  
   273  	go app.prepareCheckTx(reqCheckTx)
   274  }
   275  
   276  // BeginRecheckTx implements the ABCI interface and set the check state based on the given header
   277  func (app *BaseApp) BeginRecheckTx(req ocabci.RequestBeginRecheckTx) ocabci.ResponseBeginRecheckTx {
   278  	// NOTE: This is safe because Ostracon holds a lock on the mempool for Rechecking.
   279  	app.setCheckState(req.Header)
   280  	return ocabci.ResponseBeginRecheckTx{Code: abci.CodeTypeOK}
   281  }
   282  
   283  // EndRecheckTx implements the ABCI interface.
   284  func (app *BaseApp) EndRecheckTx(req ocabci.RequestEndRecheckTx) ocabci.ResponseEndRecheckTx {
   285  	return ocabci.ResponseEndRecheckTx{Code: abci.CodeTypeOK}
   286  }
   287  
   288  // DeliverTx implements the ABCI interface and executes a tx in DeliverTx mode.
   289  // State only gets persisted if all messages are valid and get executed successfully.
   290  // Otherwise, the ResponseDeliverTx will contain releveant error information.
   291  // Regardless of tx execution outcome, the ResponseDeliverTx will contain relevant
   292  // gas execution context.
   293  func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliverTx) {
   294  	defer telemetry.MeasureSince(time.Now(), "abci", "deliver_tx")
   295  
   296  	defer func() {
   297  		for _, streamingListener := range app.abciListeners {
   298  			if err := streamingListener.ListenDeliverTx(app.deliverState.ctx, req, res); err != nil {
   299  				app.logger.Error("DeliverTx listening hook failed", "err", err)
   300  			}
   301  		}
   302  	}()
   303  
   304  	gInfo := sdk.GasInfo{}
   305  	resultStr := "successful"
   306  
   307  	defer func() {
   308  		telemetry.IncrCounter(1, "tx", "count")
   309  		telemetry.IncrCounter(1, "tx", resultStr)
   310  		telemetry.SetGauge(float32(gInfo.GasUsed), "tx", "gas", "used")
   311  		telemetry.SetGauge(float32(gInfo.GasWanted), "tx", "gas", "wanted")
   312  	}()
   313  
   314  	tx, err := app.txDecoder(req.Tx)
   315  	if err != nil {
   316  		return sdkerrors.ResponseDeliverTx(err, 0, 0, app.trace)
   317  	}
   318  
   319  	gInfo, result, anteEvents, err := app.runTx(req.Tx, tx, false)
   320  	if err != nil {
   321  		resultStr = "failed"
   322  		return sdkerrors.ResponseDeliverTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, sdk.MarkEventsToIndex(anteEvents, app.indexEvents), app.trace)
   323  	}
   324  
   325  	return abci.ResponseDeliverTx{
   326  		GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints?
   327  		GasUsed:   int64(gInfo.GasUsed),   // TODO: Should type accept unsigned ints?
   328  		Log:       result.Log,
   329  		Data:      result.Data,
   330  		Events:    sdk.MarkEventsToIndex(result.Events, app.indexEvents),
   331  	}
   332  }
   333  
   334  // Commit implements the ABCI interface. It will commit all state that exists in
   335  // the deliver state's multi-store and includes the resulting commit ID in the
   336  // returned abci.ResponseCommit. Commit will reset the deliver state.
   337  // Also, if a non-zero halt height is defined in config, Commit will execute
   338  // a deferred function call to check against that height and gracefully halt if
   339  // it matches the latest committed height.
   340  func (app *BaseApp) Commit() (res abci.ResponseCommit) {
   341  	defer telemetry.MeasureSince(time.Now(), "abci", "commit")
   342  
   343  	header := app.deliverState.ctx.BlockHeader()
   344  	retainHeight := app.GetBlockRetentionHeight(header.Height)
   345  
   346  	// Write the DeliverTx state into branched storage and commit the MultiStore.
   347  	// The write to the DeliverTx state writes all state transitions to the root
   348  	// MultiStore (app.cms) so when Commit() is called is persists those values.
   349  	app.deliverState.ms.Write()
   350  	commitID := app.cms.Commit()
   351  	app.logger.Info("commit synced", "commit", fmt.Sprintf("%X", commitID))
   352  
   353  	// empty/reset the deliver state
   354  	app.deliverState = nil
   355  
   356  	var halt bool
   357  
   358  	switch {
   359  	case app.haltHeight > 0 && uint64(header.Height) >= app.haltHeight:
   360  		halt = true
   361  
   362  	case app.haltTime > 0 && header.Time.Unix() >= int64(app.haltTime):
   363  		halt = true
   364  	}
   365  
   366  	if halt {
   367  		// Halt the binary and allow Tendermint to receive the ResponseCommit
   368  		// response with the commit ID hash. This will allow the node to successfully
   369  		// restart and process blocks assuming the halt configuration has been
   370  		// reset or moved to a more distant value.
   371  		app.halt()
   372  	}
   373  
   374  	if app.snapshotInterval > 0 && uint64(header.Height)%app.snapshotInterval == 0 {
   375  		go app.snapshot(header.Height)
   376  	}
   377  
   378  	return abci.ResponseCommit{
   379  		Data:         commitID.Hash,
   380  		RetainHeight: retainHeight,
   381  	}
   382  }
   383  
   384  // halt attempts to gracefully shutdown the node via SIGINT and SIGTERM falling
   385  // back on os.Exit if both fail.
   386  func (app *BaseApp) halt() {
   387  	app.logger.Info("halting node per configuration", "height", app.haltHeight, "time", app.haltTime)
   388  
   389  	p, err := os.FindProcess(os.Getpid())
   390  	if err == nil {
   391  		// attempt cascading signals in case SIGINT fails (os dependent)
   392  		sigIntErr := p.Signal(syscall.SIGINT)
   393  		sigTermErr := p.Signal(syscall.SIGTERM)
   394  
   395  		if sigIntErr == nil || sigTermErr == nil {
   396  			return
   397  		}
   398  	}
   399  
   400  	// Resort to exiting immediately if the process could not be found or killed
   401  	// via SIGINT/SIGTERM signals.
   402  	app.logger.Info("failed to send SIGINT/SIGTERM; exiting...")
   403  	os.Exit(0)
   404  }
   405  
   406  // snapshot takes a snapshot of the current state and prunes any old snapshottypes.
   407  func (app *BaseApp) snapshot(height int64) {
   408  	if app.snapshotManager == nil {
   409  		app.logger.Info("snapshot manager not configured")
   410  		return
   411  	}
   412  
   413  	app.logger.Info("creating state snapshot", "height", height)
   414  
   415  	snapshot, err := app.snapshotManager.Create(uint64(height))
   416  	if err != nil {
   417  		app.logger.Error("failed to create state snapshot", "height", height, "err", err)
   418  		return
   419  	}
   420  
   421  	app.logger.Info("completed state snapshot", "height", height, "format", snapshot.Format)
   422  
   423  	if app.snapshotKeepRecent > 0 {
   424  		app.logger.Debug("pruning state snapshots")
   425  
   426  		pruned, err := app.snapshotManager.Prune(app.snapshotKeepRecent)
   427  		if err != nil {
   428  			app.logger.Error("Failed to prune state snapshots", "err", err)
   429  			return
   430  		}
   431  
   432  		app.logger.Debug("pruned state snapshots", "pruned", pruned)
   433  	}
   434  }
   435  
   436  // Query implements the ABCI interface. It delegates to CommitMultiStore if it
   437  // implements Queryable.
   438  func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
   439  	defer telemetry.MeasureSince(time.Now(), "abci", "query")
   440  
   441  	// Add panic recovery for all queries.
   442  	// ref: https://github.com/cosmos/cosmos-sdk/pull/8039
   443  	defer func() {
   444  		if r := recover(); r != nil {
   445  			res = sdkerrors.QueryResultWithDebug(sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r), app.trace)
   446  		}
   447  	}()
   448  
   449  	// when a client did not provide a query height, manually inject the latest
   450  	if req.Height == 0 {
   451  		req.Height = app.LastBlockHeight()
   452  	}
   453  
   454  	// handle gRPC routes first rather than calling splitPath because '/' characters
   455  	// are used as part of gRPC paths
   456  	if grpcHandler := app.grpcQueryRouter.Route(req.Path); grpcHandler != nil {
   457  		return app.handleQueryGRPC(grpcHandler, req)
   458  	}
   459  
   460  	path := splitPath(req.Path)
   461  	if len(path) == 0 {
   462  		return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no query path provided"), app.trace)
   463  	}
   464  
   465  	switch path[0] {
   466  	// "/app" prefix for special application queries
   467  	case "app":
   468  		return handleQueryApp(app, path, req)
   469  
   470  	case "store":
   471  		return handleQueryStore(app, path, req)
   472  
   473  	case "p2p":
   474  		return handleQueryP2P(app, path)
   475  
   476  	case "custom":
   477  		return handleQueryCustom(app, path, req)
   478  	}
   479  
   480  	return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query path"), app.trace)
   481  }
   482  
   483  // ListSnapshots implements the ABCI interface. It delegates to app.snapshotManager if set.
   484  func (app *BaseApp) ListSnapshots(req abci.RequestListSnapshots) abci.ResponseListSnapshots {
   485  	resp := abci.ResponseListSnapshots{Snapshots: []*abci.Snapshot{}}
   486  	if app.snapshotManager == nil {
   487  		return resp
   488  	}
   489  
   490  	snapshots, err := app.snapshotManager.List()
   491  	if err != nil {
   492  		app.logger.Error("failed to list snapshots", "err", err)
   493  		return resp
   494  	}
   495  
   496  	for _, snapshot := range snapshots {
   497  		abciSnapshot, err := snapshot.ToABCI()
   498  		if err != nil {
   499  			app.logger.Error("failed to list snapshots", "err", err)
   500  			return resp
   501  		}
   502  		resp.Snapshots = append(resp.Snapshots, &abciSnapshot)
   503  	}
   504  
   505  	return resp
   506  }
   507  
   508  // LoadSnapshotChunk implements the ABCI interface. It delegates to app.snapshotManager if set.
   509  func (app *BaseApp) LoadSnapshotChunk(req abci.RequestLoadSnapshotChunk) abci.ResponseLoadSnapshotChunk {
   510  	if app.snapshotManager == nil {
   511  		return abci.ResponseLoadSnapshotChunk{}
   512  	}
   513  	chunk, err := app.snapshotManager.LoadChunk(req.Height, req.Format, req.Chunk)
   514  	if err != nil {
   515  		app.logger.Error(
   516  			"failed to load snapshot chunk",
   517  			"height", req.Height,
   518  			"format", req.Format,
   519  			"chunk", req.Chunk,
   520  			"err", err,
   521  		)
   522  		return abci.ResponseLoadSnapshotChunk{}
   523  	}
   524  	return abci.ResponseLoadSnapshotChunk{Chunk: chunk}
   525  }
   526  
   527  // OfferSnapshot implements the ABCI interface. It delegates to app.snapshotManager if set.
   528  func (app *BaseApp) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOfferSnapshot {
   529  	if app.snapshotManager == nil {
   530  		app.logger.Error("snapshot manager not configured")
   531  		return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ABORT}
   532  	}
   533  
   534  	if req.Snapshot == nil {
   535  		app.logger.Error("received nil snapshot")
   536  		return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}
   537  	}
   538  
   539  	snapshot, err := snapshottypes.SnapshotFromABCI(req.Snapshot)
   540  	if err != nil {
   541  		app.logger.Error("failed to decode snapshot metadata", "err", err)
   542  		return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}
   543  	}
   544  
   545  	err = app.snapshotManager.Restore(snapshot)
   546  	switch {
   547  	case err == nil:
   548  		return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ACCEPT}
   549  
   550  	case errors.Is(err, snapshottypes.ErrUnknownFormat):
   551  		return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT_FORMAT}
   552  
   553  	case errors.Is(err, snapshottypes.ErrInvalidMetadata):
   554  		app.logger.Error(
   555  			"rejecting invalid snapshot",
   556  			"height", req.Snapshot.Height,
   557  			"format", req.Snapshot.Format,
   558  			"err", err,
   559  		)
   560  		return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}
   561  
   562  	default:
   563  		app.logger.Error(
   564  			"failed to restore snapshot",
   565  			"height", req.Snapshot.Height,
   566  			"format", req.Snapshot.Format,
   567  			"err", err,
   568  		)
   569  
   570  		// We currently don't support resetting the IAVL stores and retrying a different snapshot,
   571  		// so we ask Tendermint to abort all snapshot restoration.
   572  		return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ABORT}
   573  	}
   574  }
   575  
   576  // ApplySnapshotChunk implements the ABCI interface. It delegates to app.snapshotManager if set.
   577  func (app *BaseApp) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci.ResponseApplySnapshotChunk {
   578  	if app.snapshotManager == nil {
   579  		app.logger.Error("snapshot manager not configured")
   580  		return abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ABORT}
   581  	}
   582  
   583  	_, err := app.snapshotManager.RestoreChunk(req.Chunk)
   584  	switch {
   585  	case err == nil:
   586  		return abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}
   587  
   588  	case errors.Is(err, snapshottypes.ErrChunkHashMismatch):
   589  		app.logger.Error(
   590  			"chunk checksum mismatch; rejecting sender and requesting refetch",
   591  			"chunk", req.Index,
   592  			"sender", req.Sender,
   593  			"err", err,
   594  		)
   595  		return abci.ResponseApplySnapshotChunk{
   596  			Result:        abci.ResponseApplySnapshotChunk_RETRY,
   597  			RefetchChunks: []uint32{req.Index},
   598  			RejectSenders: []string{req.Sender},
   599  		}
   600  
   601  	default:
   602  		app.logger.Error("failed to restore snapshot", "err", err)
   603  		return abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ABORT}
   604  	}
   605  }
   606  
   607  func (app *BaseApp) handleQueryGRPC(handler GRPCQueryHandler, req abci.RequestQuery) abci.ResponseQuery {
   608  	ctx, err := app.createQueryContext(req.Height, req.Prove)
   609  	if err != nil {
   610  		return sdkerrors.QueryResultWithDebug(err, app.trace)
   611  	}
   612  
   613  	res, err := handler(ctx, req)
   614  	if err != nil {
   615  		res = sdkerrors.QueryResultWithDebug(gRPCErrorToSDKError(err), app.trace)
   616  		res.Height = req.Height
   617  		return res
   618  	}
   619  
   620  	return res
   621  }
   622  
   623  func gRPCErrorToSDKError(err error) error {
   624  	status, ok := grpcstatus.FromError(err)
   625  	if !ok {
   626  		return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
   627  	}
   628  
   629  	switch status.Code() {
   630  	case codes.NotFound:
   631  		return sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, err.Error())
   632  	case codes.InvalidArgument:
   633  		return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
   634  	case codes.FailedPrecondition:
   635  		return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
   636  	case codes.Unauthenticated:
   637  		return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, err.Error())
   638  	default:
   639  		return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, err.Error())
   640  	}
   641  }
   642  
   643  func checkNegativeHeight(height int64) error {
   644  	if height < 0 {
   645  		// Reject invalid heights.
   646  		return sdkerrors.Wrap(
   647  			sdkerrors.ErrInvalidRequest,
   648  			"cannot query with height < 0; please provide a valid height",
   649  		)
   650  	}
   651  	return nil
   652  }
   653  
   654  // createQueryContext creates a new sdk.Context for a query, taking as args
   655  // the block height and whether the query needs a proof or not.
   656  func (app *BaseApp) createQueryContext(height int64, prove bool) (sdk.Context, error) {
   657  	if err := checkNegativeHeight(height); err != nil {
   658  		return sdk.Context{}, err
   659  	}
   660  
   661  	lastBlockHeight := app.LastBlockHeight()
   662  	if height > lastBlockHeight {
   663  		return sdk.Context{},
   664  			sdkerrors.Wrap(
   665  				sdkerrors.ErrInvalidHeight,
   666  				"cannot query with height in the future; please provide a valid height",
   667  			)
   668  	}
   669  
   670  	// when a client did not provide a query height, manually inject the latest
   671  	if height == 0 {
   672  		height = lastBlockHeight
   673  	}
   674  
   675  	if height <= 1 && prove {
   676  		return sdk.Context{},
   677  			sdkerrors.Wrap(
   678  				sdkerrors.ErrInvalidRequest,
   679  				"cannot query with proof when height <= 1; please provide a valid height",
   680  			)
   681  	}
   682  
   683  	cacheMS, err := app.cms.CacheMultiStoreWithVersion(height)
   684  	if err != nil {
   685  		return sdk.Context{},
   686  			sdkerrors.Wrapf(
   687  				sdkerrors.ErrInvalidRequest,
   688  				"failed to load state at height %d; %s (latest height: %d)", height, err, lastBlockHeight,
   689  			)
   690  	}
   691  
   692  	// branch the commit-multistore for safety
   693  	app.checkStateMtx.RLock()
   694  	ctx := sdk.NewContext(
   695  		cacheMS, app.checkState.ctx.BlockHeader(), true, app.logger,
   696  	).WithMinGasPrices(app.minGasPrices).WithBlockHeight(height)
   697  	app.checkStateMtx.RUnlock()
   698  
   699  	return ctx, nil
   700  }
   701  
   702  // GetBlockRetentionHeight returns the height for which all blocks below this height
   703  // are pruned from Tendermint. Given a commitment height and a non-zero local
   704  // minRetainBlocks configuration, the retentionHeight is the smallest height that
   705  // satisfies:
   706  //
   707  // - Unbonding (safety threshold) time: The block interval in which validators
   708  // can be economically punished for misbehavior. Blocks in this interval must be
   709  // auditable e.g. by the light client.
   710  //
   711  // - Logical store snapshot interval: The block interval at which the underlying
   712  // logical store database is persisted to disk, e.g. every 10000 heights. Blocks
   713  // since the last IAVL snapshot must be available for replay on application restart.
   714  //
   715  // - State sync snapshots: Blocks since the oldest available snapshot must be
   716  // available for state sync nodes to catch up (oldest because a node may be
   717  // restoring an old snapshot while a new snapshot was taken).
   718  //
   719  // - Local (minRetainBlocks) config: Archive nodes may want to retain more or
   720  // all blocks, e.g. via a local config option min-retain-blocks. There may also
   721  // be a need to vary retention for other nodes, e.g. sentry nodes which do not
   722  // need historical blocks.
   723  func (app *BaseApp) GetBlockRetentionHeight(commitHeight int64) int64 {
   724  	// pruning is disabled if minRetainBlocks is zero
   725  	if app.minRetainBlocks == 0 {
   726  		return 0
   727  	}
   728  
   729  	minNonZero := func(x, y int64) int64 {
   730  		switch {
   731  		case x == 0:
   732  			return y
   733  		case y == 0:
   734  			return x
   735  		case x < y:
   736  			return x
   737  		default:
   738  			return y
   739  		}
   740  	}
   741  
   742  	// Define retentionHeight as the minimum value that satisfies all non-zero
   743  	// constraints. All blocks below (commitHeight-retentionHeight) are pruned
   744  	// from Tendermint.
   745  	var retentionHeight int64
   746  
   747  	// Define the number of blocks needed to protect against misbehaving validators
   748  	// which allows light clients to operate safely. Note, we piggy back of the
   749  	// evidence parameters instead of computing an estimated nubmer of blocks based
   750  	// on the unbonding period and block commitment time as the two should be
   751  	// equivalent.
   752  	cp := app.GetConsensusParams(app.deliverState.ctx)
   753  	if cp != nil && cp.Evidence != nil && cp.Evidence.MaxAgeNumBlocks > 0 {
   754  		retentionHeight = commitHeight - cp.Evidence.MaxAgeNumBlocks
   755  	}
   756  
   757  	// Define the state pruning offset, i.e. the block offset at which the
   758  	// underlying logical database is persisted to disk.
   759  	statePruningOffset := int64(app.cms.GetPruning().KeepEvery)
   760  	if statePruningOffset > 0 {
   761  		if commitHeight > statePruningOffset {
   762  			v := commitHeight - (commitHeight % statePruningOffset)
   763  			retentionHeight = minNonZero(retentionHeight, v)
   764  		} else {
   765  			// Hitting this case means we have persisting enabled but have yet to reach
   766  			// a height in which we persist state, so we return zero regardless of other
   767  			// conditions. Otherwise, we could end up pruning blocks without having
   768  			// any state committed to disk.
   769  			return 0
   770  		}
   771  	}
   772  
   773  	if app.snapshotInterval > 0 && app.snapshotKeepRecent > 0 {
   774  		v := commitHeight - int64((app.snapshotInterval * uint64(app.snapshotKeepRecent)))
   775  		retentionHeight = minNonZero(retentionHeight, v)
   776  	}
   777  
   778  	v := commitHeight - int64(app.minRetainBlocks)
   779  	retentionHeight = minNonZero(retentionHeight, v)
   780  
   781  	if retentionHeight <= 0 {
   782  		// prune nothing in the case of a non-positive height
   783  		return 0
   784  	}
   785  
   786  	return retentionHeight
   787  }
   788  
   789  func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery {
   790  	if len(path) >= 2 {
   791  		switch path[1] {
   792  		case "simulate":
   793  			txBytes := req.Data
   794  
   795  			gInfo, res, err := app.Simulate(txBytes)
   796  			if err != nil {
   797  				return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(err, "failed to simulate tx"), app.trace)
   798  			}
   799  
   800  			simRes := &sdk.SimulationResponse{
   801  				GasInfo: gInfo,
   802  				Result:  res,
   803  			}
   804  
   805  			bz, err := codec.ProtoMarshalJSON(simRes, app.interfaceRegistry)
   806  			if err != nil {
   807  				return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(err, "failed to JSON encode simulation response"), app.trace)
   808  			}
   809  
   810  			return abci.ResponseQuery{
   811  				Codespace: sdkerrors.RootCodespace,
   812  				Height:    req.Height,
   813  				Value:     bz,
   814  			}
   815  
   816  		case "version":
   817  			return abci.ResponseQuery{
   818  				Codespace: sdkerrors.RootCodespace,
   819  				Height:    req.Height,
   820  				Value:     []byte(app.version),
   821  			}
   822  
   823  		case "snapshots":
   824  			var responseValue []byte
   825  
   826  			response := app.ListSnapshots(abci.RequestListSnapshots{})
   827  
   828  			responseValue, err := json.Marshal(response)
   829  			if err != nil {
   830  				sdkerrors.QueryResult(sdkerrors.Wrap(err, fmt.Sprintf("failed to marshal list snapshots response %v", response)))
   831  			}
   832  
   833  			return abci.ResponseQuery{
   834  				Codespace: sdkerrors.RootCodespace,
   835  				Height:    req.Height,
   836  				Value:     responseValue,
   837  			}
   838  
   839  		default:
   840  			return sdkerrors.QueryResultWithDebug(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query: %s", path), app.trace)
   841  		}
   842  	}
   843  
   844  	return sdkerrors.QueryResultWithDebug(
   845  		sdkerrors.Wrap(
   846  			sdkerrors.ErrUnknownRequest,
   847  			"expected second parameter to be either 'simulate' or 'version', neither was present",
   848  		), app.trace)
   849  }
   850  
   851  func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery {
   852  	// "/store" prefix for store queries
   853  	queryable, ok := app.cms.(sdk.Queryable)
   854  	if !ok {
   855  		return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries"), app.trace)
   856  	}
   857  
   858  	req.Path = "/" + strings.Join(path[1:], "/")
   859  
   860  	if req.Height <= 1 && req.Prove {
   861  		return sdkerrors.QueryResultWithDebug(
   862  			sdkerrors.Wrap(
   863  				sdkerrors.ErrInvalidRequest,
   864  				"cannot query with proof when height <= 1; please provide a valid height",
   865  			), app.trace)
   866  	}
   867  
   868  	resp := queryable.Query(req)
   869  	resp.Height = req.Height
   870  
   871  	return resp
   872  }
   873  
   874  func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery {
   875  	// path[0] should be "custom" because "/custom" prefix is required for keeper
   876  	// queries.
   877  	//
   878  	// The QueryRouter routes using path[1]. For example, in the path
   879  	// "custom/gov/proposal", QueryRouter routes using "gov".
   880  	if len(path) < 2 || path[1] == "" {
   881  		return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no route for custom query specified"), app.trace)
   882  	}
   883  
   884  	querier := app.queryRouter.Route(path[1])
   885  	if querier == nil {
   886  		return sdkerrors.QueryResultWithDebug(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no custom querier found for route %s", path[1]), app.trace)
   887  	}
   888  
   889  	ctx, err := app.createQueryContext(req.Height, req.Prove)
   890  	if err != nil {
   891  		return sdkerrors.QueryResultWithDebug(err, app.trace)
   892  	}
   893  
   894  	// Passes the rest of the path as an argument to the querier.
   895  	//
   896  	// For example, in the path "custom/gov/proposal/test", the gov querier gets
   897  	// []string{"proposal", "test"} as the path.
   898  	resBytes, err := querier(ctx, path[2:], req)
   899  	if err != nil {
   900  		res := sdkerrors.QueryResultWithDebug(err, app.trace)
   901  		res.Height = req.Height
   902  		return res
   903  	}
   904  
   905  	return abci.ResponseQuery{
   906  		Height: req.Height,
   907  		Value:  resBytes,
   908  	}
   909  }
   910  
   911  // splitPath splits a string path using the delimiter '/'.
   912  //
   913  // e.g. "this/is/funny" becomes []string{"this", "is", "funny"}
   914  func splitPath(requestPath string) (path []string) {
   915  	path = strings.Split(requestPath, "/")
   916  
   917  	// first element is empty string
   918  	if len(path) > 0 && path[0] == "" {
   919  		path = path[1:]
   920  	}
   921  
   922  	return path
   923  }
   924  
   925  // createQueryContext creates a new sdk.Context for a query, taking as args
   926  // the block height and whether the query needs a proof or not.
   927  func (app *BaseApp) createQueryContextWithCheckState() sdk.Context {
   928  
   929  	cacheMS := app.checkState.CacheMultiStore()
   930  
   931  	// branch the commit-multistore for safety
   932  	app.checkStateMtx.RLock()
   933  	ctx := sdk.NewContext(
   934  		cacheMS, app.checkState.ctx.BlockHeader(), true, app.logger,
   935  	).WithMinGasPrices(app.minGasPrices).WithBlockHeight(app.LastBlockHeight())
   936  	app.checkStateMtx.RUnlock()
   937  
   938  	return ctx
   939  }