diff --git a/CHANGELOG.md b/CHANGELOG.md index ed433367ac..3fad372d84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (evm) [#450](https://github.com/crypto-org-chain/ethermint/pull/450) Refactor transient stores to be compatible with parallel tx execution. * (evm) [#454](https://github.com/crypto-org-chain/ethermint/pull/454) Migrate transient stores to object stores. * (evm) [#461](https://github.com/crypto-org-chain/ethermint/pull/461) Remove custom signer getter, use the option in protobuf file instead. +* (evm) [#469](https://github.com/crypto-org-chain/ethermint/pull/469) More aggressive cache of common parameters in object store. ## v0.21.x-cronos diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index 7b4b659265..456ed27820 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -938,6 +938,7 @@ func (suite *AnteTestSuite) TestAnteHandler() { setup() suite.ctx = suite.ctx.WithIsCheckTx(tc.checkTx).WithIsReCheckTx(tc.reCheckTx).WithConsensusParams(*app.DefaultConsensusParams) + suite.app.EvmKeeper.RemoveParamsCache(suite.ctx) // expConsumed := params.TxGasContractCreation + params.TxGas _, err := suite.anteHandler(suite.ctx, tc.txFn(), false) diff --git a/app/ante/eth.go b/app/ante/eth.go index bca039ea49..2622733461 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -101,18 +101,13 @@ func VerifyEthAccount( // - gas limit is greater than the block gas meter limit func CheckEthGasConsume( ctx sdk.Context, tx sdk.Tx, - ethCfg *params.ChainConfig, + rules params.Rules, evmKeeper EVMKeeper, baseFee *big.Int, maxGasWanted uint64, evmDenom string, ) (sdk.Context, error) { gasWanted := uint64(0) - - blockHeight := big.NewInt(ctx.BlockHeight()) - homestead := ethCfg.IsHomestead(blockHeight) - istanbul := ethCfg.IsIstanbul(blockHeight) - shanghai := ethCfg.IsShanghai(uint64(ctx.BlockHeader().Time.Unix())) var events sdk.Events // Use the lowest priority of all the messages as the final one. @@ -152,7 +147,7 @@ func CheckEthGasConsume( continue } - fees, err := keeper.VerifyFee(txData, evmDenom, baseFee, homestead, istanbul, shanghai, ctx.IsCheckTx()) + fees, err := keeper.VerifyFee(txData, evmDenom, baseFee, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai, ctx.IsCheckTx()) if err != nil { return ctx, errorsmod.Wrapf(err, "failed to verify the fees") } @@ -207,7 +202,7 @@ func CheckEthGasConsume( func CheckEthCanTransfer( ctx sdk.Context, tx sdk.Tx, baseFee *big.Int, - ethCfg *params.ChainConfig, + rules params.Rules, evmKeeper EVMKeeper, evmParams *evmtypes.Params, ) error { @@ -225,7 +220,7 @@ func CheckEthCanTransfer( ) } - if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) { + if rules.IsLondon { if baseFee == nil { return errorsmod.Wrap( evmtypes.ErrInvalidBaseFee, diff --git a/app/ante/eth_test.go b/app/ante/eth_test.go index 00534e868b..ac329be5de 100644 --- a/app/ante/eth_test.go +++ b/app/ante/eth_test.go @@ -161,6 +161,7 @@ func (suite *AnteTestSuite) TestEthGasConsumeDecorator() { chainCfg := evmParams.GetChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) baseFee := suite.app.EvmKeeper.GetBaseFee(suite.ctx, ethCfg) + rules := ethCfg.Rules(big.NewInt(suite.ctx.BlockHeight()), ethCfg.MergeNetsplitBlock != nil, uint64(suite.ctx.BlockHeader().Time.Unix())) addr := tests.GenerateAddress() @@ -298,7 +299,7 @@ func (suite *AnteTestSuite) TestEthGasConsumeDecorator() { suite.Require().Panics(func() { _, _ = ante.CheckEthGasConsume( suite.ctx.WithIsCheckTx(true).WithGasMeter(storetypes.NewGasMeter(1)), tc.tx, - ethCfg, suite.app.EvmKeeper, baseFee, config.DefaultMaxTxGasWanted, evmtypes.DefaultEVMDenom, + rules, suite.app.EvmKeeper, baseFee, config.DefaultMaxTxGasWanted, evmtypes.DefaultEVMDenom, ) }) return @@ -306,7 +307,7 @@ func (suite *AnteTestSuite) TestEthGasConsumeDecorator() { ctx, err := ante.CheckEthGasConsume( suite.ctx.WithIsCheckTx(true).WithGasMeter(storetypes.NewInfiniteGasMeter()), tc.tx, - ethCfg, suite.app.EvmKeeper, baseFee, config.DefaultMaxTxGasWanted, evmtypes.DefaultEVMDenom, + rules, suite.app.EvmKeeper, baseFee, config.DefaultMaxTxGasWanted, evmtypes.DefaultEVMDenom, ) if tc.expPass { suite.Require().NoError(err) @@ -328,6 +329,7 @@ func (suite *AnteTestSuite) TestCanTransferDecorator() { chainCfg := evmParams.GetChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) baseFee := suite.app.EvmKeeper.GetBaseFee(suite.ctx, ethCfg) + rules := ethCfg.Rules(big.NewInt(suite.ctx.BlockHeight()), ethCfg.MergeNetsplitBlock != nil, uint64(suite.ctx.BlockHeader().Time.Unix())) tx := evmtypes.NewTxContract( suite.app.EvmKeeper.ChainID(), @@ -397,7 +399,7 @@ func (suite *AnteTestSuite) TestCanTransferDecorator() { err := ante.CheckEthCanTransfer( suite.ctx.WithIsCheckTx(true), tc.tx, - baseFee, ethCfg, suite.app.EvmKeeper, &evmParams, + baseFee, rules, suite.app.EvmKeeper, &evmParams, ) if tc.expPass { diff --git a/app/ante/handler_options.go b/app/ante/handler_options.go index 76a5e4d2d0..ce2cfb839b 100644 --- a/app/ante/handler_options.go +++ b/app/ante/handler_options.go @@ -71,14 +71,16 @@ func (options HandlerOptions) validate() error { func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler { return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { - var err error - evmParams := options.EvmKeeper.GetParams(ctx) + blockCfg, err := options.EvmKeeper.EVMBlockConfig(ctx, options.EvmKeeper.ChainID()) + if err != nil { + return ctx, errorsmod.Wrap(errortypes.ErrLogic, err.Error()) + } + evmParams := &blockCfg.Params evmDenom := evmParams.EvmDenom - feemarketParams := options.FeeMarketKeeper.GetParams(ctx) - chainID := options.EvmKeeper.ChainID() - chainCfg := evmParams.GetChainConfig() - ethCfg := chainCfg.EthereumConfig(chainID) - baseFee := evmtypes.GetBaseFee(ctx.BlockHeight(), ethCfg, &feemarketParams) + feemarketParams := &blockCfg.FeeMarketParams + chainID := blockCfg.ChainConfig.ChainID + baseFee := blockCfg.BaseFee + rules := blockCfg.Rules // all transactions must implement FeeTx _, ok := tx.(sdk.FeeTx) @@ -100,7 +102,7 @@ func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler { return ctx, err } - if err := ValidateEthBasic(ctx, tx, &evmParams, baseFee); err != nil { + if err := ValidateEthBasic(ctx, tx, evmParams, baseFee); err != nil { return ctx, err } @@ -112,12 +114,12 @@ func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler { return ctx, err } - if err := CheckEthCanTransfer(ctx, tx, baseFee, ethCfg, options.EvmKeeper, &evmParams); err != nil { + if err := CheckEthCanTransfer(ctx, tx, baseFee, rules, options.EvmKeeper, evmParams); err != nil { return ctx, err } ctx, err = CheckEthGasConsume( - ctx, tx, ethCfg, options.EvmKeeper, + ctx, tx, rules, options.EvmKeeper, baseFee, options.MaxTxGasWanted, evmDenom, ) if err != nil { diff --git a/app/ante/interfaces.go b/app/ante/interfaces.go index a68b6eb2d3..c81683daa0 100644 --- a/app/ante/interfaces.go +++ b/app/ante/interfaces.go @@ -22,6 +22,7 @@ import ( tx "github.com/cosmos/cosmos-sdk/types/tx" "github.com/ethereum/go-ethereum/common" + evmkeeper "github.com/evmos/ethermint/x/evm/keeper" "github.com/evmos/ethermint/x/evm/statedb" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" ) @@ -30,6 +31,7 @@ import ( type EVMKeeper interface { statedb.Keeper ChainID() *big.Int + EVMBlockConfig(sdk.Context, *big.Int) (*evmkeeper.EVMBlockConfig, error) DeductTxCostsFromUserBalance(ctx sdk.Context, fees sdk.Coins, from common.Address) error } diff --git a/app/app.go b/app/app.go index ea2c676f7d..f26950ab71 100644 --- a/app/app.go +++ b/app/app.go @@ -335,7 +335,7 @@ func NewEthermintApp( // Add the EVM transient store key tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) - okeys := storetypes.NewObjectStoreKeys(banktypes.ObjectStoreKey, evmtypes.ObjectStoreKey, feemarkettypes.ObjectStoreKey) + okeys := storetypes.NewObjectStoreKeys(banktypes.ObjectStoreKey, evmtypes.ObjectStoreKey) // load state streaming if enabled if err := bApp.RegisterStreamingServices(appOpts, keys); err != nil { @@ -510,7 +510,7 @@ func NewEthermintApp( app.FeeMarketKeeper = feemarketkeeper.NewKeeper( appCodec, authtypes.NewModuleAddress(govtypes.ModuleName), - keys[feemarkettypes.StoreKey], okeys[feemarkettypes.ObjectStoreKey], + keys[feemarkettypes.StoreKey], feeMarketSs, ) diff --git a/tests/integration_tests/test_grpc_only.py b/tests/integration_tests/test_grpc_only.py index c2216f5c14..1fb0105c30 100644 --- a/tests/integration_tests/test_grpc_only.py +++ b/tests/integration_tests/test_grpc_only.py @@ -111,10 +111,9 @@ def expect_cb(rsp): wait_for_port(api_port) def expect_cb(rsp): - assert rsp["code"] != 0, str(rsp) - return "validator does not exist" in rsp["message"] + return "code" not in rsp - # it don't works without proposer address neither + # it defaults to empty address without proposer address grpc_eth_call(api_port, msg, expect_cb, chain_id=9000) # pass the first validator's consensus address to grpc query diff --git a/x/evm/keeper/abci.go b/x/evm/keeper/abci.go index 0f64bf25cb..d890eb53f3 100644 --- a/x/evm/keeper/abci.go +++ b/x/evm/keeper/abci.go @@ -23,8 +23,10 @@ import ( func (k *Keeper) BeginBlock(ctx sdk.Context) error { k.WithChainID(ctx) - // cache params object - _ = k.GetParams(ctx) + // cache parameters that's common for the whole block. + if _, err := k.EVMBlockConfig(ctx, k.ChainID()); err != nil { + return err + } return nil } @@ -34,5 +36,6 @@ func (k *Keeper) BeginBlock(ctx sdk.Context) error { // an empty slice. func (k *Keeper) EndBlock(ctx sdk.Context) error { k.CollectTxBloom(ctx) + k.RemoveParamsCache(ctx) return nil } diff --git a/x/evm/keeper/config.go b/x/evm/keeper/config.go index 0c441092c1..0f0e589ff7 100644 --- a/x/evm/keeper/config.go +++ b/x/evm/keeper/config.go @@ -30,41 +30,54 @@ import ( feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" ) -// EVMConfig encapsulates common parameters needed to create an EVM to execute a message -// It's mainly to reduce the number of method parameters -type EVMConfig struct { +// EVMBlockConfig encapsulates the common parameters needed to execute an EVM message, +// it's cached in object store during the block execution. +type EVMBlockConfig struct { Params types.Params FeeMarketParams feemarkettypes.Params ChainConfig *params.ChainConfig CoinBase common.Address BaseFee *big.Int - TxConfig statedb.TxConfig - Tracer vm.EVMLogger - DebugTrace bool - Overrides *rpctypes.StateOverride - BlockOverrides *rpctypes.BlockOverrides + // not supported, always zero + Random *common.Hash + // unused, always zero + Difficulty *big.Int + // cache the big.Int version of block number, avoid repeated allocation + BlockNumber *big.Int + BlockTime uint64 + Rules params.Rules } -// EVMConfig creates the EVMConfig based on current state -func (k *Keeper) EVMConfig(ctx sdk.Context, proposerAddress sdk.ConsAddress, chainID *big.Int, txHash common.Hash) (*EVMConfig, error) { +// EVMConfig encapsulates common parameters needed to create an EVM to execute a message +// It's mainly to reduce the number of method parameters +type EVMConfig struct { + *EVMBlockConfig + TxConfig statedb.TxConfig + Tracer vm.EVMLogger + DebugTrace bool + Overrides *rpctypes.StateOverride + BlockOverrides *rpctypes.BlockOverrides +} + +// EVMBlockConfig creates the EVMBlockConfig based on current state +func (k *Keeper) EVMBlockConfig(ctx sdk.Context, chainID *big.Int) (*EVMBlockConfig, error) { + objStore := ctx.ObjectStore(k.objectKey) + v := objStore.Get(types.KeyPrefixObjectParams) + if v != nil { + return v.(*EVMBlockConfig), nil + } + params := k.GetParams(ctx) ethCfg := params.ChainConfig.EthereumConfig(chainID) feemarketParams := k.feeMarketKeeper.GetParams(ctx) // get the coinbase address from the block proposer - coinbase, err := k.GetCoinbaseAddress(ctx, proposerAddress) + coinbase, err := k.GetCoinbaseAddress(ctx) if err != nil { return nil, errorsmod.Wrap(err, "failed to obtain coinbase address") } - var txConfig statedb.TxConfig - if txHash == (common.Hash{}) { - txConfig = statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) - } else { - txConfig = k.TxConfig(ctx, txHash) - } - var baseFee *big.Int if types.IsLondon(ethCfg, ctx.BlockHeight()) { baseFee = feemarketParams.GetBaseFee() @@ -74,13 +87,48 @@ func (k *Keeper) EVMConfig(ctx sdk.Context, proposerAddress sdk.ConsAddress, cha } } - return &EVMConfig{ + blockTime := uint64(ctx.BlockHeader().Time.Unix()) + blockNumber := big.NewInt(ctx.BlockHeight()) + rules := ethCfg.Rules(blockNumber, ethCfg.MergeNetsplitBlock != nil, blockTime) + + var zero common.Hash + cfg := &EVMBlockConfig{ Params: params, FeeMarketParams: feemarketParams, ChainConfig: ethCfg, CoinBase: coinbase, BaseFee: baseFee, - TxConfig: txConfig, + Difficulty: big.NewInt(0), + Random: &zero, + BlockNumber: blockNumber, + BlockTime: blockTime, + Rules: rules, + } + objStore.Set(types.KeyPrefixObjectParams, cfg) + return cfg, nil +} + +func (k *Keeper) RemoveParamsCache(ctx sdk.Context) { + ctx.ObjectStore(k.objectKey).Delete(types.KeyPrefixObjectParams) +} + +// EVMConfig creates the EVMConfig based on current state +func (k *Keeper) EVMConfig(ctx sdk.Context, chainID *big.Int, txHash common.Hash) (*EVMConfig, error) { + blockCfg, err := k.EVMBlockConfig(ctx, chainID) + if err != nil { + return nil, err + } + + var txConfig statedb.TxConfig + if txHash == (common.Hash{}) { + txConfig = statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) + } else { + txConfig = k.TxConfig(ctx, txHash) + } + + return &EVMConfig{ + EVMBlockConfig: blockCfg, + TxConfig: txConfig, }, nil } diff --git a/x/evm/keeper/gas.go b/x/evm/keeper/gas.go index 66042d7f98..5874f77002 100644 --- a/x/evm/keeper/gas.go +++ b/x/evm/keeper/gas.go @@ -31,13 +31,8 @@ import ( ) // GetEthIntrinsicGas returns the intrinsic gas cost for the transaction -func (k *Keeper) GetEthIntrinsicGas(ctx sdk.Context, msg core.Message, cfg *params.ChainConfig, isContractCreation bool) (uint64, error) { - height := big.NewInt(ctx.BlockHeight()) - homestead := cfg.IsHomestead(height) - istanbul := cfg.IsIstanbul(height) - shanghai := cfg.IsShanghai(uint64(ctx.BlockHeader().Time.Unix())) - - return core.IntrinsicGas(msg.Data, msg.AccessList, isContractCreation, homestead, istanbul, shanghai) +func (k *Keeper) GetEthIntrinsicGas(msg core.Message, rules params.Rules, isContractCreation bool) (uint64, error) { + return core.IntrinsicGas(msg.Data, msg.AccessList, isContractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) } // RefundGas transfers the leftover gas to the sender of the message, caped to half of the total gas diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 265a31abcf..8fb28c58cd 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -235,6 +235,7 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms } ctx := sdk.UnwrapSDKContext(c) + ctx = ctx.WithProposer(GetProposerAddress(ctx, req.ProposerAddress)) var args types.TransactionArgs err := json.Unmarshal(req.Args, &args) @@ -245,7 +246,7 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } - cfg, err := k.EVMConfig(ctx, GetProposerAddress(ctx, req.ProposerAddress), chainID, common.Hash{}) + cfg, err := k.EVMConfig(ctx, chainID, common.Hash{}) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -284,6 +285,7 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type } ctx := sdk.UnwrapSDKContext(c) + ctx = ctx.WithProposer(GetProposerAddress(ctx, req.ProposerAddress)) chainID, err := getChainID(ctx, req.ChainId) if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) @@ -326,7 +328,7 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type hi = req.GasCap } gasCap = hi - cfg, err := k.EVMConfig(ctx, GetProposerAddress(ctx, req.ProposerAddress), chainID, common.Hash{}) + cfg, err := k.EVMConfig(ctx, chainID, common.Hash{}) if err != nil { return nil, status.Error(codes.Internal, "failed to load evm config") } @@ -441,12 +443,13 @@ func execTrace[T traceRequest]( ctx = ctx.WithBlockHeight(contextHeight) ctx = ctx.WithBlockTime(req.GetBlockTime()) ctx = ctx.WithHeaderHash(common.Hex2Bytes(req.GetBlockHash())) + ctx = ctx.WithProposer(GetProposerAddress(ctx, req.GetProposerAddress())) chainID, err := getChainID(ctx, req.GetChainId()) if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } - cfg, err := k.EVMConfig(ctx, GetProposerAddress(ctx, req.GetProposerAddress()), chainID, common.Hash{}) + cfg, err := k.EVMConfig(ctx, chainID, common.Hash{}) if err != nil { return nil, status.Errorf(codes.Internal, "failed to load evm config: %s", err.Error()) } @@ -537,12 +540,13 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest) ctx = ctx.WithBlockHeight(contextHeight) ctx = ctx.WithBlockTime(req.BlockTime) ctx = ctx.WithHeaderHash(common.Hex2Bytes(req.BlockHash)) + ctx = ctx.WithProposer(GetProposerAddress(ctx, req.ProposerAddress)) chainID, err := getChainID(ctx, req.ChainId) if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } - cfg, err := k.EVMConfig(ctx, GetProposerAddress(ctx, req.ProposerAddress), chainID, common.Hash{}) + cfg, err := k.EVMConfig(ctx, chainID, common.Hash{}) if err != nil { return nil, status.Error(codes.Internal, "failed to load evm config") } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index ec9771a5ed..14fee66b9c 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -199,8 +199,8 @@ func (k *Keeper) PostTxProcessing(ctx sdk.Context, msg core.Message, receipt *et } // Tracer return a default vm.Tracer based on current keeper state -func (k Keeper) Tracer(ctx sdk.Context, msg core.Message, ethCfg *params.ChainConfig) vm.EVMLogger { - return types.NewTracer(k.tracer, msg, ethCfg, ctx.BlockHeight(), ctx.BlockHeader().Time.Unix()) +func (k Keeper) Tracer(msg core.Message, rules params.Rules) vm.EVMLogger { + return types.NewTracer(k.tracer, msg, rules) } // GetAccount load nonce and codehash without balance, diff --git a/x/evm/keeper/params.go b/x/evm/keeper/params.go index 2691b409fa..bcbb01cb40 100644 --- a/x/evm/keeper/params.go +++ b/x/evm/keeper/params.go @@ -23,20 +23,13 @@ import ( // GetParams returns the total set of evm parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { - var params types.Params - objStore := ctx.ObjectStore(k.objectKey) - v := objStore.Get(types.KeyPrefixObjectParams) - if v == nil { - bz := ctx.KVStore(k.storeKey).Get(types.KeyPrefixParams) - if len(bz) != 0 { - k.cdc.MustUnmarshal(bz, ¶ms) - } else { - params = k.GetLegacyParams(ctx) - } - objStore.Set(types.KeyPrefixObjectParams, ¶ms) - } else { - params = *(v.(*types.Params)) + bz := ctx.KVStore(k.storeKey).Get(types.KeyPrefixParams) + if len(bz) == 0 { + return k.GetLegacyParams(ctx) } + + var params types.Params + k.cdc.MustUnmarshal(bz, ¶ms) return params } @@ -48,12 +41,6 @@ func (k Keeper) SetParams(ctx sdk.Context, p types.Params) error { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshal(&p) store.Set(types.KeyPrefixParams, bz) - - // set to cache as well, decode again to be compatible with the previous behavior - var params types.Params - k.cdc.MustUnmarshal(bz, ¶ms) - ctx.ObjectStore(k.objectKey).Set(types.KeyPrefixObjectParams, ¶ms) - return nil } diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index f1c466085f..9f6d75db46 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -52,36 +52,34 @@ func (k *Keeper) NewEVM( cfg *EVMConfig, stateDB vm.StateDB, ) *vm.EVM { - zero := common.BigToHash(big.NewInt(0)) blockCtx := vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: statedb.Transfer, GetHash: k.GetHashFn(ctx), Coinbase: cfg.CoinBase, GasLimit: ethermint.BlockGasLimit(ctx), - BlockNumber: big.NewInt(ctx.BlockHeight()), - Time: uint64(ctx.BlockHeader().Time.Unix()), - Difficulty: big.NewInt(0), // unused. Only required in PoW context + BlockNumber: cfg.BlockNumber, + Time: cfg.BlockTime, + Difficulty: cfg.Difficulty, BaseFee: cfg.BaseFee, - Random: &zero, // not supported + Random: cfg.Random, } if cfg.BlockOverrides != nil { cfg.BlockOverrides.Apply(&blockCtx) } txCtx := core.NewEVMTxContext(&msg) if cfg.Tracer == nil { - cfg.Tracer = k.Tracer(ctx, msg, cfg.ChainConfig) + cfg.Tracer = k.Tracer(msg, cfg.Rules) } vmConfig := k.VMConfig(ctx, msg, cfg) - rules := cfg.ChainConfig.Rules(big.NewInt(ctx.BlockHeight()), cfg.ChainConfig.MergeNetsplitBlock != nil, blockCtx.Time) contracts := make(map[common.Address]vm.PrecompiledContract) active := make([]common.Address, 0) - for addr, c := range vm.DefaultPrecompiles(rules) { + for addr, c := range vm.DefaultPrecompiles(cfg.Rules) { contracts[addr] = c active = append(active, addr) } for _, fn := range k.customContractFns { - c := fn(ctx, rules) + c := fn(ctx, cfg.Rules) addr := c.Address() contracts[addr] = c active = append(active, addr) @@ -169,7 +167,7 @@ func (k Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc { // For relevant discussion see: https://github.com/cosmos/cosmos-sdk/discussions/9072 func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) (*types.MsgEthereumTxResponse, error) { ethTx := msgEth.AsTransaction() - cfg, err := k.EVMConfig(ctx, sdk.ConsAddress(ctx.BlockHeader().ProposerAddress), k.eip155ChainID, ethTx.Hash()) + cfg, err := k.EVMConfig(ctx, k.eip155ChainID, ethTx.Hash()) if err != nil { return nil, errorsmod.Wrap(err, "failed to load evm config") } @@ -216,7 +214,7 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) ContractAddress: contractAddr, GasUsed: res.GasUsed, BlockHash: cfg.TxConfig.BlockHash, - BlockNumber: big.NewInt(ctx.BlockHeight()), + BlockNumber: cfg.BlockNumber, } if !res.Failed() { @@ -254,7 +252,7 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) // ApplyMessage calls ApplyMessageWithConfig with an empty TxConfig. func (k *Keeper) ApplyMessage(ctx sdk.Context, msg core.Message, tracer vm.EVMLogger, commit bool) (*types.MsgEthereumTxResponse, error) { - cfg, err := k.EVMConfig(ctx, sdk.ConsAddress(ctx.BlockHeader().ProposerAddress), k.eip155ChainID, common.Hash{}) + cfg, err := k.EVMConfig(ctx, k.eip155ChainID, common.Hash{}) if err != nil { return nil, errorsmod.Wrap(err, "failed to load evm config") } @@ -355,9 +353,9 @@ func (k *Keeper) ApplyMessageWithConfig( }() } - isLondon := cfg.ChainConfig.IsLondon(evm.Context.BlockNumber) + rules := cfg.Rules contractCreation := msg.To == nil - intrinsicGas, err := k.GetEthIntrinsicGas(ctx, msg, cfg.ChainConfig, contractCreation) + intrinsicGas, err := k.GetEthIntrinsicGas(msg, rules, contractCreation) if err != nil { // should have already been checked on Ante Handler return nil, errorsmod.Wrap(err, "intrinsic gas failed") @@ -372,8 +370,6 @@ func (k *Keeper) ApplyMessageWithConfig( // access list preparation is moved from ante handler to here, because it's needed when `ApplyMessage` is called // under contexts where ante handlers are not run, for example `eth_call` and `eth_estimateGas`. - time := uint64(ctx.BlockHeader().Time.Unix()) - rules := cfg.ChainConfig.Rules(big.NewInt(ctx.BlockHeight()), cfg.ChainConfig.MergeNetsplitBlock != nil, time) // Check whether the init code size has been exceeded. if rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSize { return nil, fmt.Errorf("%w: code size %v limit %v", core.ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize) @@ -398,7 +394,7 @@ func (k *Keeper) ApplyMessageWithConfig( refundQuotient := params.RefundQuotient // After EIP-3529: refunds are capped to gasUsed / 5 - if isLondon { + if rules.IsLondon { refundQuotient = params.RefundQuotientEIP3529 } diff --git a/x/evm/keeper/state_transition_test.go b/x/evm/keeper/state_transition_test.go index c7a4ba3aad..2c381fd87e 100644 --- a/x/evm/keeper/state_transition_test.go +++ b/x/evm/keeper/state_transition_test.go @@ -182,7 +182,7 @@ func (suite *StateTransitionTestSuite) TestGetCoinbaseAddress() { "validator not found", func() { header := suite.Ctx.BlockHeader() - header.ProposerAddress = []byte{} + header.ProposerAddress = []byte{1} suite.Ctx = suite.Ctx.WithBlockHeader(header).WithConsensusParams(*app.DefaultConsensusParams) }, false, @@ -221,8 +221,7 @@ func (suite *StateTransitionTestSuite) TestGetCoinbaseAddress() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset tc.malleate() - proposerAddress := suite.Ctx.BlockHeader().ProposerAddress - coinbase, err := suite.App.EvmKeeper.GetCoinbaseAddress(suite.Ctx, sdk.ConsAddress(proposerAddress)) + coinbase, err := suite.App.EvmKeeper.GetCoinbaseAddress(suite.Ctx) if tc.expPass { suite.Require().NoError(err) suite.Require().Equal(valOpAddr, coinbase) @@ -345,7 +344,8 @@ func (suite *StateTransitionTestSuite) TestGetEthIntrinsicGas() { ) suite.Require().NoError(err) - gas, err := suite.App.EvmKeeper.GetEthIntrinsicGas(suite.Ctx, m, ethCfg, tc.isContractCreation) + rules := ethCfg.Rules(big.NewInt(suite.Ctx.BlockHeight()), ethCfg.MergeNetsplitBlock != nil, uint64(suite.Ctx.BlockHeader().Time.Unix())) + gas, err := suite.App.EvmKeeper.GetEthIntrinsicGas(m, rules, tc.isContractCreation) if tc.noError { suite.Require().NoError(err) } else { @@ -584,8 +584,7 @@ func (suite *StateTransitionTestSuite) TestResetGasMeterAndConsumeGas() { func (suite *StateTransitionTestSuite) TestEVMConfig() { suite.SetupTest() - proposerAddress := suite.Ctx.BlockHeader().ProposerAddress - cfg, err := suite.App.EvmKeeper.EVMConfig(suite.Ctx, proposerAddress, big.NewInt(9000), common.Hash{}) + cfg, err := suite.App.EvmKeeper.EVMConfig(suite.Ctx, big.NewInt(9000), common.Hash{}) suite.Require().NoError(err) suite.Require().Equal(types.DefaultParams(), cfg.Params) // london hardfork is enabled by default @@ -609,14 +608,14 @@ func (suite *StateTransitionTestSuite) TestApplyMessage() { expectedGasUsed := params.TxGas var msg core.Message - proposerAddress := suite.Ctx.BlockHeader().ProposerAddress - config, err := suite.App.EvmKeeper.EVMConfig(suite.Ctx, proposerAddress, big.NewInt(9000), common.Hash{}) + _, err := suite.App.EvmKeeper.EVMConfig(suite.Ctx, big.NewInt(9000), common.Hash{}) suite.Require().NoError(err) keeperParams := suite.App.EvmKeeper.GetParams(suite.Ctx) chainCfg := keeperParams.ChainConfig.EthereumConfig(suite.App.EvmKeeper.ChainID()) + rules := chainCfg.Rules(big.NewInt(suite.Ctx.BlockHeight()), chainCfg.MergeNetsplitBlock != nil, uint64(suite.Ctx.BlockHeader().Time.Unix())) signer := ethtypes.LatestSignerForChainID(suite.App.EvmKeeper.ChainID()) - tracer := suite.App.EvmKeeper.Tracer(suite.Ctx, msg, config.ChainConfig) + tracer := suite.App.EvmKeeper.Tracer(msg, rules) vmdb := suite.StateDB() msg, err = newNativeMessage( @@ -709,8 +708,7 @@ func (suite *StateTransitionTestSuite) TestApplyMessageWithConfig() { suite.SetupTest() expectedGasUsed = params.TxGas - proposerAddress := suite.Ctx.BlockHeader().ProposerAddress - config, err = suite.App.EvmKeeper.EVMConfig(suite.Ctx, proposerAddress, big.NewInt(9000), common.Hash{}) + config, err = suite.App.EvmKeeper.EVMConfig(suite.Ctx, big.NewInt(9000), common.Hash{}) suite.Require().NoError(err) keeperParams = suite.App.EvmKeeper.GetParams(suite.Ctx) diff --git a/x/evm/keeper/utils.go b/x/evm/keeper/utils.go index 96f03660cc..9720232bf0 100644 --- a/x/evm/keeper/utils.go +++ b/x/evm/keeper/utils.go @@ -34,8 +34,13 @@ import ( ) // GetCoinbaseAddress returns the block proposer's validator operator address. -func (k Keeper) GetCoinbaseAddress(ctx sdk.Context, proposerAddress sdk.ConsAddress) (common.Address, error) { - validator, err := k.stakingKeeper.GetValidatorByConsAddr(ctx, GetProposerAddress(ctx, proposerAddress)) +func (k Keeper) GetCoinbaseAddress(ctx sdk.Context) (common.Address, error) { + proposerAddress := sdk.ConsAddress(ctx.BlockHeader().ProposerAddress) + if len(proposerAddress) == 0 { + // it's ok that proposer address don't exsits in some contexts like CheckTx. + return common.Address{}, nil + } + validator, err := k.stakingKeeper.GetValidatorByConsAddr(ctx, proposerAddress) if err != nil { return common.Address{}, errorsmod.Wrapf( stakingtypes.ErrNoValidatorFound, diff --git a/x/evm/types/key.go b/x/evm/types/key.go index 73f896dbd6..51b19a469a 100644 --- a/x/evm/types/key.go +++ b/x/evm/types/key.go @@ -63,7 +63,8 @@ var ( var ( KeyPrefixObjectBloom = []byte{prefixObjectBloom} KeyPrefixObjectGasUsed = []byte{prefixObjectGasUsed} - KeyPrefixObjectParams = []byte{prefixObjectParams} + // cache the `EVMBlockConfig` during the whole block execution + KeyPrefixObjectParams = []byte{prefixObjectParams} ) // AddressStoragePrefix returns a prefix to iterate over a given account storage. diff --git a/x/evm/types/tracer.go b/x/evm/types/tracer.go index d8269e6fb9..ace4b4e224 100644 --- a/x/evm/types/tracer.go +++ b/x/evm/types/tracer.go @@ -36,7 +36,7 @@ const ( // NewTracer creates a new Logger tracer to collect execution traces from an // EVM transaction. -func NewTracer(tracer string, msg core.Message, cfg *params.ChainConfig, height, time int64) vm.EVMLogger { +func NewTracer(tracer string, msg core.Message, rules params.Rules) vm.EVMLogger { // TODO: enable additional log configuration logCfg := &logger.Config{ Debug: true, @@ -44,7 +44,7 @@ func NewTracer(tracer string, msg core.Message, cfg *params.ChainConfig, height, switch tracer { case TracerAccessList: - preCompiles := vm.DefaultActivePrecompiles(cfg.Rules(big.NewInt(height), cfg.MergeNetsplitBlock != nil, uint64(time))) + preCompiles := vm.DefaultActivePrecompiles(rules) return logger.NewAccessListTracer(msg.AccessList, msg.From, *msg.To, preCompiles) case TracerJSON: return logger.NewJSONLogger(logCfg, os.Stderr) diff --git a/x/feemarket/keeper/keeper.go b/x/feemarket/keeper/keeper.go index 6bed111d1a..94730358e1 100644 --- a/x/feemarket/keeper/keeper.go +++ b/x/feemarket/keeper/keeper.go @@ -34,7 +34,7 @@ type Keeper struct { // Protobuf codec cdc codec.BinaryCodec // Store key required for the Fee Market Prefix KVStore. - storeKey, objectKey storetypes.StoreKey + storeKey storetypes.StoreKey // the address capable of executing a MsgUpdateParams message. Typically, this should be the x/gov module account. authority sdk.AccAddress // Legacy subspace @@ -45,7 +45,7 @@ type Keeper struct { func NewKeeper( cdc codec.BinaryCodec, authority sdk.AccAddress, - storeKey, objectKey storetypes.StoreKey, + storeKey storetypes.StoreKey, ss paramstypes.Subspace, ) Keeper { // ensure authority account is correctly formatted @@ -56,7 +56,6 @@ func NewKeeper( return Keeper{ cdc: cdc, storeKey: storeKey, - objectKey: objectKey, authority: authority, ss: ss, } diff --git a/x/feemarket/keeper/params.go b/x/feemarket/keeper/params.go index 705d4f84f1..82d76f806a 100644 --- a/x/feemarket/keeper/params.go +++ b/x/feemarket/keeper/params.go @@ -27,18 +27,11 @@ import ( // GetParams returns the total set of fee market parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { var params types.Params - objStore := ctx.ObjectStore(k.objectKey) - v := objStore.Get(types.KeyPrefixObjectParams) - if v == nil { - bz := ctx.KVStore(k.storeKey).Get(types.ParamsKey) - if len(bz) != 0 { - k.cdc.MustUnmarshal(bz, ¶ms) - } else { - k.ss.GetParamSetIfExists(ctx, ¶ms) - } - objStore.Set(types.KeyPrefixObjectParams, ¶ms) + bz := ctx.KVStore(k.storeKey).Get(types.ParamsKey) + if len(bz) == 0 { + k.ss.GetParamSetIfExists(ctx, ¶ms) } else { - params = *(v.(*types.Params)) + k.cdc.MustUnmarshal(bz, ¶ms) } return params } @@ -52,11 +45,6 @@ func (k Keeper) SetParams(ctx sdk.Context, p types.Params) error { bz := k.cdc.MustMarshal(&p) store.Set(types.ParamsKey, bz) - // set to cache as well, decode again to be compatible with the previous behavior - var params types.Params - k.cdc.MustUnmarshal(bz, ¶ms) - ctx.ObjectStore(k.objectKey).Set(types.KeyPrefixObjectParams, ¶ms) - return nil } diff --git a/x/feemarket/types/keys.go b/x/feemarket/types/keys.go index 82b7514cbe..2ca00de870 100644 --- a/x/feemarket/types/keys.go +++ b/x/feemarket/types/keys.go @@ -25,9 +25,6 @@ const ( // RouterKey uses module name for routing RouterKey = ModuleName - - // ObjectStoreKey is the key to access the Fee Market object store - ObjectStoreKey = "object:" + ModuleName ) // prefix bytes for the feemarket persistent store @@ -36,17 +33,7 @@ const ( deprecatedPrefixBaseFee // unused ) -// prefix bytes for the feemarket object store -const ( - prefixObjectParams = iota + 1 -) - // KVStore key prefixes var ( KeyPrefixBlockGasWanted = []byte{prefixBlockGasWanted} ) - -// Object store key prefixes -var ( - KeyPrefixObjectParams = []byte{prefixObjectParams} -)