github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/context.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package protocol
     7  
     8  import (
     9  	"context"
    10  	"math/big"
    11  	"time"
    12  
    13  	"github.com/ethereum/go-ethereum/core/vm"
    14  	"github.com/iotexproject/go-pkgs/hash"
    15  	"github.com/iotexproject/iotex-address/address"
    16  
    17  	"github.com/iotexproject/iotex-core/blockchain/genesis"
    18  	"github.com/iotexproject/iotex-core/pkg/log"
    19  )
    20  
    21  type (
    22  	blockchainContextKey struct{}
    23  
    24  	blockContextKey struct{}
    25  
    26  	actionContextKey struct{}
    27  
    28  	registryContextKey struct{}
    29  
    30  	featureContextKey struct{}
    31  
    32  	featureWithHeightContextKey struct{}
    33  
    34  	vmConfigContextKey struct{}
    35  
    36  	// TipInfo contains the tip block information
    37  	TipInfo struct {
    38  		Height    uint64
    39  		Hash      hash.Hash256
    40  		Timestamp time.Time
    41  	}
    42  
    43  	// BlockchainCtx provides blockchain auxiliary information.
    44  	BlockchainCtx struct {
    45  		// Tip is the information of tip block
    46  		Tip TipInfo
    47  		//ChainID is the native chain ID
    48  		ChainID uint32
    49  		// EvmNetworkID is the EVM network ID
    50  		EvmNetworkID uint32
    51  	}
    52  
    53  	// BlockCtx provides block auxiliary information.
    54  	BlockCtx struct {
    55  		// height of block containing those actions
    56  		BlockHeight uint64
    57  		// timestamp of block containing those actions
    58  		BlockTimeStamp time.Time
    59  		// gas Limit for perform those actions
    60  		GasLimit uint64
    61  		// Producer is the address of whom composes the block containing this action
    62  		Producer address.Address
    63  	}
    64  
    65  	// ActionCtx provides action auxiliary information.
    66  	ActionCtx struct {
    67  		// Caller is the address of whom issues this action
    68  		Caller address.Address
    69  		// ActionHash is the hash of the action with the sealed envelope
    70  		ActionHash hash.Hash256
    71  		// GasPrice is the action gas price
    72  		GasPrice *big.Int
    73  		// IntrinsicGas is the action intrinsic gas
    74  		IntrinsicGas uint64
    75  		// Nonce is the nonce of the action
    76  		Nonce uint64
    77  	}
    78  
    79  	// CheckFunc is function type to check by height.
    80  	CheckFunc func(height uint64) bool
    81  
    82  	// FeatureCtx provides features information.
    83  	FeatureCtx struct {
    84  		FixDoubleChargeGas                      bool
    85  		SystemWideActionGasLimit                bool
    86  		NotFixTopicCopyBug                      bool
    87  		SetRevertMessageToReceipt               bool
    88  		FixGetHashFnHeight                      bool
    89  		FixSortCacheContractsAndUsePendingNonce bool
    90  		AsyncContractTrie                       bool
    91  		AddOutOfGasToTransactionLog             bool
    92  		AddChainIDToConfig                      bool
    93  		UseV2Storage                            bool
    94  		CannotUnstakeAgain                      bool
    95  		SkipStakingIndexer                      bool
    96  		ReturnFetchError                        bool
    97  		CannotTranferToSelf                     bool
    98  		NewStakingReceiptFormat                 bool
    99  		UpdateBlockMeta                         bool
   100  		CurrentEpochProductivity                bool
   101  		FixSnapshotOrder                        bool
   102  		AllowCorrectDefaultChainID              bool
   103  		CorrectGetHashFn                        bool
   104  		CorrectTxLogIndex                       bool
   105  		RevertLog                               bool
   106  		TolerateLegacyAddress                   bool
   107  		CreateLegacyNonceAccount                bool
   108  		FixGasAndNonceUpdate                    bool
   109  		FixUnproductiveDelegates                bool
   110  		CorrectGasRefund                        bool
   111  		SkipSystemActionNonce                   bool
   112  		ValidateSystemAction                    bool
   113  		AllowCorrectChainIDOnly                 bool
   114  		AddContractStakingVotes                 bool
   115  		FixContractStakingWeightedVotes         bool
   116  		ExecutionSizeLimit32KB                  bool
   117  		UseZeroNonceForFreshAccount             bool
   118  		SharedGasWithDapp                       bool
   119  		CandidateRegisterMustWithStake          bool
   120  		DisableDelegateEndorsement              bool
   121  		RefactorFreshAccountConversion          bool
   122  		SuicideTxLogMismatchPanic               bool
   123  	}
   124  
   125  	// FeatureWithHeightCtx provides feature check functions.
   126  	FeatureWithHeightCtx struct {
   127  		GetUnproductiveDelegates CheckFunc
   128  		ReadStateFromDB          CheckFunc
   129  		UseV2Staking             CheckFunc
   130  		EnableNativeStaking      CheckFunc
   131  		StakingCorrectGas        CheckFunc
   132  		CalculateProbationList   CheckFunc
   133  		LoadCandidatesLegacy     CheckFunc
   134  		CandCenterHasAlias       CheckFunc
   135  	}
   136  )
   137  
   138  // WithRegistry adds registry to context
   139  func WithRegistry(ctx context.Context, reg *Registry) context.Context {
   140  	return context.WithValue(ctx, registryContextKey{}, reg)
   141  }
   142  
   143  // GetRegistry returns the registry from context
   144  func GetRegistry(ctx context.Context) (*Registry, bool) {
   145  	reg, ok := ctx.Value(registryContextKey{}).(*Registry)
   146  	return reg, ok
   147  }
   148  
   149  // MustGetRegistry returns the registry from context
   150  func MustGetRegistry(ctx context.Context) *Registry {
   151  	reg, ok := ctx.Value(registryContextKey{}).(*Registry)
   152  	if !ok {
   153  		log.S().Panic("Miss registry context")
   154  	}
   155  	return reg
   156  }
   157  
   158  // WithBlockchainCtx add BlockchainCtx into context.
   159  func WithBlockchainCtx(ctx context.Context, bc BlockchainCtx) context.Context {
   160  	return context.WithValue(ctx, blockchainContextKey{}, bc)
   161  }
   162  
   163  // GetBlockchainCtx gets BlockchainCtx
   164  func GetBlockchainCtx(ctx context.Context) (BlockchainCtx, bool) {
   165  	bc, ok := ctx.Value(blockchainContextKey{}).(BlockchainCtx)
   166  	return bc, ok
   167  }
   168  
   169  // MustGetBlockchainCtx must get BlockchainCtx.
   170  // If context doesn't exist, this function panic.
   171  func MustGetBlockchainCtx(ctx context.Context) BlockchainCtx {
   172  	bc, ok := ctx.Value(blockchainContextKey{}).(BlockchainCtx)
   173  	if !ok {
   174  		log.S().Panic("Miss blockchain context")
   175  	}
   176  	return bc
   177  }
   178  
   179  // WithBlockCtx add BlockCtx into context.
   180  func WithBlockCtx(ctx context.Context, blk BlockCtx) context.Context {
   181  	return context.WithValue(ctx, blockContextKey{}, blk)
   182  }
   183  
   184  // GetBlockCtx gets BlockCtx
   185  func GetBlockCtx(ctx context.Context) (BlockCtx, bool) {
   186  	blk, ok := ctx.Value(blockContextKey{}).(BlockCtx)
   187  	return blk, ok
   188  }
   189  
   190  // MustGetBlockCtx must get BlockCtx .
   191  // If context doesn't exist, this function panic.
   192  func MustGetBlockCtx(ctx context.Context) BlockCtx {
   193  	blk, ok := ctx.Value(blockContextKey{}).(BlockCtx)
   194  	if !ok {
   195  		log.S().Panic("Miss block context")
   196  	}
   197  	return blk
   198  }
   199  
   200  // WithActionCtx add ActionCtx into context.
   201  func WithActionCtx(ctx context.Context, ac ActionCtx) context.Context {
   202  	return context.WithValue(ctx, actionContextKey{}, ac)
   203  }
   204  
   205  // GetActionCtx gets ActionCtx
   206  func GetActionCtx(ctx context.Context) (ActionCtx, bool) {
   207  	ac, ok := ctx.Value(actionContextKey{}).(ActionCtx)
   208  	return ac, ok
   209  }
   210  
   211  // MustGetActionCtx must get ActionCtx .
   212  // If context doesn't exist, this function panic.
   213  func MustGetActionCtx(ctx context.Context) ActionCtx {
   214  	ac, ok := ctx.Value(actionContextKey{}).(ActionCtx)
   215  	if !ok {
   216  		log.S().Panic("Miss action context")
   217  	}
   218  	return ac
   219  }
   220  
   221  // WithFeatureCtx add FeatureCtx into context.
   222  func WithFeatureCtx(ctx context.Context) context.Context {
   223  	g := genesis.MustExtractGenesisContext(ctx)
   224  	height := MustGetBlockCtx(ctx).BlockHeight
   225  	return context.WithValue(
   226  		ctx,
   227  		featureContextKey{},
   228  		FeatureCtx{
   229  			FixDoubleChargeGas:                      g.IsPacific(height),
   230  			SystemWideActionGasLimit:                !g.IsAleutian(height),
   231  			NotFixTopicCopyBug:                      !g.IsAleutian(height),
   232  			SetRevertMessageToReceipt:               g.IsHawaii(height),
   233  			FixGetHashFnHeight:                      g.IsHawaii(height),
   234  			FixSortCacheContractsAndUsePendingNonce: g.IsHawaii(height),
   235  			AsyncContractTrie:                       g.IsGreenland(height),
   236  			AddOutOfGasToTransactionLog:             !g.IsGreenland(height),
   237  			AddChainIDToConfig:                      g.IsIceland(height),
   238  			UseV2Storage:                            g.IsGreenland(height),
   239  			CannotUnstakeAgain:                      g.IsGreenland(height),
   240  			SkipStakingIndexer:                      !g.IsFairbank(height),
   241  			ReturnFetchError:                        !g.IsGreenland(height),
   242  			CannotTranferToSelf:                     g.IsHawaii(height),
   243  			NewStakingReceiptFormat:                 g.IsFbkMigration(height),
   244  			UpdateBlockMeta:                         g.IsGreenland(height),
   245  			CurrentEpochProductivity:                g.IsGreenland(height),
   246  			FixSnapshotOrder:                        g.IsKamchatka(height),
   247  			AllowCorrectDefaultChainID:              g.IsMidway(height),
   248  			CorrectGetHashFn:                        g.IsMidway(height),
   249  			CorrectTxLogIndex:                       g.IsMidway(height),
   250  			RevertLog:                               g.IsMidway(height),
   251  			TolerateLegacyAddress:                   !g.IsNewfoundland(height),
   252  			CreateLegacyNonceAccount:                !g.IsOkhotsk(height),
   253  			FixGasAndNonceUpdate:                    g.IsOkhotsk(height),
   254  			FixUnproductiveDelegates:                g.IsOkhotsk(height),
   255  			CorrectGasRefund:                        g.IsOkhotsk(height),
   256  			SkipSystemActionNonce:                   g.IsPalau(height),
   257  			ValidateSystemAction:                    g.IsQuebec(height),
   258  			AllowCorrectChainIDOnly:                 g.IsQuebec(height),
   259  			AddContractStakingVotes:                 g.IsQuebec(height),
   260  			FixContractStakingWeightedVotes:         g.IsRedsea(height),
   261  			ExecutionSizeLimit32KB:                  !g.IsSumatra(height),
   262  			UseZeroNonceForFreshAccount:             g.IsSumatra(height),
   263  			SharedGasWithDapp:                       g.IsToBeEnabled(height),
   264  			CandidateRegisterMustWithStake:          !g.IsTsunami(height),
   265  			DisableDelegateEndorsement:              !g.IsTsunami(height),
   266  			RefactorFreshAccountConversion:          g.IsTsunami(height),
   267  			SuicideTxLogMismatchPanic:               g.IsToBeEnabled(height),
   268  		},
   269  	)
   270  }
   271  
   272  // GetFeatureCtx gets FeatureCtx.
   273  func GetFeatureCtx(ctx context.Context) (FeatureCtx, bool) {
   274  	fc, ok := ctx.Value(featureContextKey{}).(FeatureCtx)
   275  	return fc, ok
   276  }
   277  
   278  // MustGetFeatureCtx must get FeatureCtx.
   279  // If context doesn't exist, this function panic.
   280  func MustGetFeatureCtx(ctx context.Context) FeatureCtx {
   281  	fc, ok := ctx.Value(featureContextKey{}).(FeatureCtx)
   282  	if !ok {
   283  		log.S().Panic("Miss feature context")
   284  	}
   285  	return fc
   286  }
   287  
   288  // WithFeatureWithHeightCtx add FeatureWithHeightCtx into context.
   289  func WithFeatureWithHeightCtx(ctx context.Context) context.Context {
   290  	g := genesis.MustExtractGenesisContext(ctx)
   291  	return context.WithValue(
   292  		ctx,
   293  		featureWithHeightContextKey{},
   294  		FeatureWithHeightCtx{
   295  			GetUnproductiveDelegates: func(height uint64) bool {
   296  				return !g.IsEaster(height)
   297  			},
   298  			ReadStateFromDB: func(height uint64) bool {
   299  				return g.IsGreenland(height)
   300  			},
   301  			UseV2Staking: func(height uint64) bool {
   302  				return g.IsFairbank(height)
   303  			},
   304  			EnableNativeStaking: func(height uint64) bool {
   305  				return g.IsCook(height)
   306  			},
   307  			StakingCorrectGas: func(height uint64) bool {
   308  				return g.IsDaytona(height)
   309  			},
   310  			CalculateProbationList: func(height uint64) bool {
   311  				return g.IsEaster(height)
   312  			},
   313  			LoadCandidatesLegacy: func(height uint64) bool {
   314  				return !g.IsEaster(height)
   315  			},
   316  			CandCenterHasAlias: func(height uint64) bool {
   317  				return !g.IsOkhotsk(height)
   318  			},
   319  		},
   320  	)
   321  }
   322  
   323  // GetFeatureWithHeightCtx gets FeatureWithHeightCtx.
   324  func GetFeatureWithHeightCtx(ctx context.Context) (FeatureWithHeightCtx, bool) {
   325  	fc, ok := ctx.Value(featureWithHeightContextKey{}).(FeatureWithHeightCtx)
   326  	return fc, ok
   327  }
   328  
   329  // MustGetFeatureWithHeightCtx must get FeatureWithHeightCtx.
   330  // If context doesn't exist, this function panic.
   331  func MustGetFeatureWithHeightCtx(ctx context.Context) FeatureWithHeightCtx {
   332  	fc, ok := ctx.Value(featureWithHeightContextKey{}).(FeatureWithHeightCtx)
   333  	if !ok {
   334  		log.S().Panic("Miss feature context")
   335  	}
   336  	return fc
   337  }
   338  
   339  // WithVMConfigCtx adds vm config to context
   340  func WithVMConfigCtx(ctx context.Context, vmConfig vm.Config) context.Context {
   341  	return context.WithValue(ctx, vmConfigContextKey{}, vmConfig)
   342  }
   343  
   344  // GetVMConfigCtx returns the vm config from context
   345  func GetVMConfigCtx(ctx context.Context) (vm.Config, bool) {
   346  	cfg, ok := ctx.Value(vmConfigContextKey{}).(vm.Config)
   347  	return cfg, ok
   348  }