github.com/cosmos/cosmos-sdk@v0.50.10/types/context.go (about)

     1  package types
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	abci "github.com/cometbft/cometbft/abci/types"
     8  	cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
     9  	"github.com/cosmos/gogoproto/proto"
    10  
    11  	"cosmossdk.io/core/comet"
    12  	"cosmossdk.io/core/header"
    13  	"cosmossdk.io/log"
    14  	"cosmossdk.io/store/gaskv"
    15  	storetypes "cosmossdk.io/store/types"
    16  )
    17  
    18  // ExecMode defines the execution mode which can be set on a Context.
    19  type ExecMode uint8
    20  
    21  // All possible execution modes.
    22  const (
    23  	ExecModeCheck ExecMode = iota
    24  	ExecModeReCheck
    25  	ExecModeSimulate
    26  	ExecModePrepareProposal
    27  	ExecModeProcessProposal
    28  	ExecModeVoteExtension
    29  	ExecModeVerifyVoteExtension
    30  	ExecModeFinalize
    31  )
    32  
    33  /*
    34  Context is an immutable object contains all information needed to
    35  process a request.
    36  
    37  It contains a context.Context object inside if you want to use that,
    38  but please do not over-use it. We try to keep all data structured
    39  and standard additions here would be better just to add to the Context struct
    40  */
    41  type Context struct {
    42  	baseCtx context.Context
    43  	ms      storetypes.MultiStore
    44  	// Deprecated: Use HeaderService for height, time, and chainID and CometService for the rest
    45  	header cmtproto.Header
    46  	// Deprecated: Use HeaderService for hash
    47  	headerHash []byte
    48  	// Deprecated: Use HeaderService for chainID and CometService for the rest
    49  	chainID              string
    50  	txBytes              []byte
    51  	logger               log.Logger
    52  	voteInfo             []abci.VoteInfo
    53  	gasMeter             storetypes.GasMeter
    54  	blockGasMeter        storetypes.GasMeter
    55  	checkTx              bool
    56  	recheckTx            bool // if recheckTx == true, then checkTx must also be true
    57  	sigverifyTx          bool // when run simulation, because the private key corresponding to the account in the genesis.json randomly generated, we must skip the sigverify.
    58  	execMode             ExecMode
    59  	minGasPrice          DecCoins
    60  	consParams           cmtproto.ConsensusParams
    61  	eventManager         EventManagerI
    62  	priority             int64 // The tx priority, only relevant in CheckTx
    63  	kvGasConfig          storetypes.GasConfig
    64  	transientKVGasConfig storetypes.GasConfig
    65  	streamingManager     storetypes.StreamingManager
    66  	cometInfo            comet.BlockInfo
    67  	headerInfo           header.Info
    68  }
    69  
    70  // Proposed rename, not done to avoid API breakage
    71  type Request = Context
    72  
    73  // Read-only accessors
    74  func (c Context) Context() context.Context                      { return c.baseCtx }
    75  func (c Context) MultiStore() storetypes.MultiStore             { return c.ms }
    76  func (c Context) BlockHeight() int64                            { return c.header.Height }
    77  func (c Context) BlockTime() time.Time                          { return c.header.Time }
    78  func (c Context) ChainID() string                               { return c.chainID }
    79  func (c Context) TxBytes() []byte                               { return c.txBytes }
    80  func (c Context) Logger() log.Logger                            { return c.logger }
    81  func (c Context) VoteInfos() []abci.VoteInfo                    { return c.voteInfo }
    82  func (c Context) GasMeter() storetypes.GasMeter                 { return c.gasMeter }
    83  func (c Context) BlockGasMeter() storetypes.GasMeter            { return c.blockGasMeter }
    84  func (c Context) IsCheckTx() bool                               { return c.checkTx }
    85  func (c Context) IsReCheckTx() bool                             { return c.recheckTx }
    86  func (c Context) IsSigverifyTx() bool                           { return c.sigverifyTx }
    87  func (c Context) ExecMode() ExecMode                            { return c.execMode }
    88  func (c Context) MinGasPrices() DecCoins                        { return c.minGasPrice }
    89  func (c Context) EventManager() EventManagerI                   { return c.eventManager }
    90  func (c Context) Priority() int64                               { return c.priority }
    91  func (c Context) KVGasConfig() storetypes.GasConfig             { return c.kvGasConfig }
    92  func (c Context) TransientKVGasConfig() storetypes.GasConfig    { return c.transientKVGasConfig }
    93  func (c Context) StreamingManager() storetypes.StreamingManager { return c.streamingManager }
    94  func (c Context) CometInfo() comet.BlockInfo                    { return c.cometInfo }
    95  func (c Context) HeaderInfo() header.Info                       { return c.headerInfo }
    96  
    97  // clone the header before returning
    98  func (c Context) BlockHeader() cmtproto.Header {
    99  	msg := proto.Clone(&c.header).(*cmtproto.Header)
   100  	return *msg
   101  }
   102  
   103  // HeaderHash returns a copy of the header hash obtained during abci.RequestBeginBlock
   104  func (c Context) HeaderHash() []byte {
   105  	hash := make([]byte, len(c.headerHash))
   106  	copy(hash, c.headerHash)
   107  	return hash
   108  }
   109  
   110  func (c Context) ConsensusParams() cmtproto.ConsensusParams {
   111  	return c.consParams
   112  }
   113  
   114  func (c Context) Deadline() (deadline time.Time, ok bool) {
   115  	return c.baseCtx.Deadline()
   116  }
   117  
   118  func (c Context) Done() <-chan struct{} {
   119  	return c.baseCtx.Done()
   120  }
   121  
   122  func (c Context) Err() error {
   123  	return c.baseCtx.Err()
   124  }
   125  
   126  // create a new context
   127  func NewContext(ms storetypes.MultiStore, header cmtproto.Header, isCheckTx bool, logger log.Logger) Context {
   128  	// https://github.com/gogo/protobuf/issues/519
   129  	header.Time = header.Time.UTC()
   130  	return Context{
   131  		baseCtx:              context.Background(),
   132  		ms:                   ms,
   133  		header:               header,
   134  		chainID:              header.ChainID,
   135  		checkTx:              isCheckTx,
   136  		sigverifyTx:          true,
   137  		logger:               logger,
   138  		gasMeter:             storetypes.NewInfiniteGasMeter(),
   139  		minGasPrice:          DecCoins{},
   140  		eventManager:         NewEventManager(),
   141  		kvGasConfig:          storetypes.KVGasConfig(),
   142  		transientKVGasConfig: storetypes.TransientGasConfig(),
   143  	}
   144  }
   145  
   146  // WithContext returns a Context with an updated context.Context.
   147  func (c Context) WithContext(ctx context.Context) Context {
   148  	c.baseCtx = ctx
   149  	return c
   150  }
   151  
   152  // WithMultiStore returns a Context with an updated MultiStore.
   153  func (c Context) WithMultiStore(ms storetypes.MultiStore) Context {
   154  	c.ms = ms
   155  	return c
   156  }
   157  
   158  // WithBlockHeader returns a Context with an updated CometBFT block header in UTC time.
   159  func (c Context) WithBlockHeader(header cmtproto.Header) Context {
   160  	// https://github.com/gogo/protobuf/issues/519
   161  	header.Time = header.Time.UTC()
   162  	c.header = header
   163  	return c
   164  }
   165  
   166  // WithHeaderHash returns a Context with an updated CometBFT block header hash.
   167  func (c Context) WithHeaderHash(hash []byte) Context {
   168  	temp := make([]byte, len(hash))
   169  	copy(temp, hash)
   170  
   171  	c.headerHash = temp
   172  	return c
   173  }
   174  
   175  // WithBlockTime returns a Context with an updated CometBFT block header time in UTC with no monotonic component.
   176  // Stripping the monotonic component is for time equality.
   177  func (c Context) WithBlockTime(newTime time.Time) Context {
   178  	newHeader := c.BlockHeader()
   179  	// https://github.com/gogo/protobuf/issues/519
   180  	newHeader.Time = newTime.Round(0).UTC()
   181  	return c.WithBlockHeader(newHeader)
   182  }
   183  
   184  // WithProposer returns a Context with an updated proposer consensus address.
   185  func (c Context) WithProposer(addr ConsAddress) Context {
   186  	newHeader := c.BlockHeader()
   187  	newHeader.ProposerAddress = addr.Bytes()
   188  	return c.WithBlockHeader(newHeader)
   189  }
   190  
   191  // WithBlockHeight returns a Context with an updated block height.
   192  func (c Context) WithBlockHeight(height int64) Context {
   193  	newHeader := c.BlockHeader()
   194  	newHeader.Height = height
   195  	return c.WithBlockHeader(newHeader)
   196  }
   197  
   198  // WithChainID returns a Context with an updated chain identifier.
   199  func (c Context) WithChainID(chainID string) Context {
   200  	c.chainID = chainID
   201  	return c
   202  }
   203  
   204  // WithTxBytes returns a Context with an updated txBytes.
   205  func (c Context) WithTxBytes(txBytes []byte) Context {
   206  	c.txBytes = txBytes
   207  	return c
   208  }
   209  
   210  // WithLogger returns a Context with an updated logger.
   211  func (c Context) WithLogger(logger log.Logger) Context {
   212  	c.logger = logger
   213  	return c
   214  }
   215  
   216  // WithVoteInfos returns a Context with an updated consensus VoteInfo.
   217  func (c Context) WithVoteInfos(voteInfo []abci.VoteInfo) Context {
   218  	c.voteInfo = voteInfo
   219  	return c
   220  }
   221  
   222  // WithGasMeter returns a Context with an updated transaction GasMeter.
   223  func (c Context) WithGasMeter(meter storetypes.GasMeter) Context {
   224  	c.gasMeter = meter
   225  	return c
   226  }
   227  
   228  // WithBlockGasMeter returns a Context with an updated block GasMeter
   229  func (c Context) WithBlockGasMeter(meter storetypes.GasMeter) Context {
   230  	c.blockGasMeter = meter
   231  	return c
   232  }
   233  
   234  // WithKVGasConfig returns a Context with an updated gas configuration for
   235  // the KVStore
   236  func (c Context) WithKVGasConfig(gasConfig storetypes.GasConfig) Context {
   237  	c.kvGasConfig = gasConfig
   238  	return c
   239  }
   240  
   241  // WithTransientKVGasConfig returns a Context with an updated gas configuration for
   242  // the transient KVStore
   243  func (c Context) WithTransientKVGasConfig(gasConfig storetypes.GasConfig) Context {
   244  	c.transientKVGasConfig = gasConfig
   245  	return c
   246  }
   247  
   248  // WithIsCheckTx enables or disables CheckTx value for verifying transactions and returns an updated Context
   249  func (c Context) WithIsCheckTx(isCheckTx bool) Context {
   250  	c.checkTx = isCheckTx
   251  	c.execMode = ExecModeCheck
   252  	return c
   253  }
   254  
   255  // WithIsRecheckTx called with true will also set true on checkTx in order to
   256  // enforce the invariant that if recheckTx = true then checkTx = true as well.
   257  func (c Context) WithIsReCheckTx(isRecheckTx bool) Context {
   258  	if isRecheckTx {
   259  		c.checkTx = true
   260  	}
   261  	c.recheckTx = isRecheckTx
   262  	c.execMode = ExecModeReCheck
   263  	return c
   264  }
   265  
   266  // WithIsSigverifyTx called with true will sigverify in auth module
   267  func (c Context) WithIsSigverifyTx(isSigverifyTx bool) Context {
   268  	c.sigverifyTx = isSigverifyTx
   269  	return c
   270  }
   271  
   272  // WithExecMode returns a Context with an updated ExecMode.
   273  func (c Context) WithExecMode(m ExecMode) Context {
   274  	c.execMode = m
   275  	return c
   276  }
   277  
   278  // WithMinGasPrices returns a Context with an updated minimum gas price value
   279  func (c Context) WithMinGasPrices(gasPrices DecCoins) Context {
   280  	c.minGasPrice = gasPrices
   281  	return c
   282  }
   283  
   284  // WithConsensusParams returns a Context with an updated consensus params
   285  func (c Context) WithConsensusParams(params cmtproto.ConsensusParams) Context {
   286  	c.consParams = params
   287  	return c
   288  }
   289  
   290  // WithEventManager returns a Context with an updated event manager
   291  func (c Context) WithEventManager(em EventManagerI) Context {
   292  	c.eventManager = em
   293  	return c
   294  }
   295  
   296  // WithPriority returns a Context with an updated tx priority
   297  func (c Context) WithPriority(p int64) Context {
   298  	c.priority = p
   299  	return c
   300  }
   301  
   302  // WithStreamingManager returns a Context with an updated streaming manager
   303  func (c Context) WithStreamingManager(sm storetypes.StreamingManager) Context {
   304  	c.streamingManager = sm
   305  	return c
   306  }
   307  
   308  // WithCometInfo returns a Context with an updated comet info
   309  func (c Context) WithCometInfo(cometInfo comet.BlockInfo) Context {
   310  	c.cometInfo = cometInfo
   311  	return c
   312  }
   313  
   314  // WithHeaderInfo returns a Context with an updated header info
   315  func (c Context) WithHeaderInfo(headerInfo header.Info) Context {
   316  	// Settime to UTC
   317  	headerInfo.Time = headerInfo.Time.UTC()
   318  	c.headerInfo = headerInfo
   319  	return c
   320  }
   321  
   322  // TODO: remove???
   323  func (c Context) IsZero() bool {
   324  	return c.ms == nil
   325  }
   326  
   327  func (c Context) WithValue(key, value interface{}) Context {
   328  	c.baseCtx = context.WithValue(c.baseCtx, key, value)
   329  	return c
   330  }
   331  
   332  func (c Context) Value(key interface{}) interface{} {
   333  	if key == SdkContextKey {
   334  		return c
   335  	}
   336  
   337  	return c.baseCtx.Value(key)
   338  }
   339  
   340  // ----------------------------------------------------------------------------
   341  // Store / Caching
   342  // ----------------------------------------------------------------------------
   343  
   344  // KVStore fetches a KVStore from the MultiStore.
   345  func (c Context) KVStore(key storetypes.StoreKey) storetypes.KVStore {
   346  	return gaskv.NewStore(c.ms.GetKVStore(key), c.gasMeter, c.kvGasConfig)
   347  }
   348  
   349  // TransientStore fetches a TransientStore from the MultiStore.
   350  func (c Context) TransientStore(key storetypes.StoreKey) storetypes.KVStore {
   351  	return gaskv.NewStore(c.ms.GetKVStore(key), c.gasMeter, c.transientKVGasConfig)
   352  }
   353  
   354  // CacheContext returns a new Context with the multi-store cached and a new
   355  // EventManager. The cached context is written to the context when writeCache
   356  // is called. Note, events are automatically emitted on the parent context's
   357  // EventManager when the caller executes the write.
   358  func (c Context) CacheContext() (cc Context, writeCache func()) {
   359  	cms := c.ms.CacheMultiStore()
   360  	cc = c.WithMultiStore(cms).WithEventManager(NewEventManager())
   361  
   362  	writeCache = func() {
   363  		c.EventManager().EmitEvents(cc.EventManager().Events())
   364  		cms.Write()
   365  	}
   366  
   367  	return cc, writeCache
   368  }
   369  
   370  var (
   371  	_ context.Context    = Context{}
   372  	_ storetypes.Context = Context{}
   373  )
   374  
   375  // ContextKey defines a type alias for a stdlib Context key.
   376  type ContextKey string
   377  
   378  // SdkContextKey is the key in the context.Context which holds the sdk.Context.
   379  const SdkContextKey ContextKey = "sdk-context"
   380  
   381  // WrapSDKContext returns a stdlib context.Context with the provided sdk.Context's internal
   382  // context as a value. It is useful for passing an sdk.Context  through methods that take a
   383  // stdlib context.Context parameter such as generated gRPC methods. To get the original
   384  // sdk.Context back, call UnwrapSDKContext.
   385  //
   386  // Deprecated: there is no need to wrap anymore as the Cosmos SDK context implements context.Context.
   387  func WrapSDKContext(ctx Context) context.Context {
   388  	return ctx
   389  }
   390  
   391  // UnwrapSDKContext retrieves a Context from a context.Context instance
   392  // attached with WrapSDKContext. It panics if a Context was not properly
   393  // attached
   394  func UnwrapSDKContext(ctx context.Context) Context {
   395  	if sdkCtx, ok := ctx.(Context); ok {
   396  		return sdkCtx
   397  	}
   398  	return ctx.Value(SdkContextKey).(Context)
   399  }