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 }