evm, rpc: disable BaseFee for non London block (#662)

* disable basefee if not london block

* add london block check in state transition

* fix linter

* add unit test

* clean code

* add changelog
This commit is contained in:
Thomas Nguy 2021-10-13 22:39:47 +09:00 committed by GitHub
parent c7a2fb97c7
commit 75d553674c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 96 additions and 17 deletions

View File

@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features ### Features
* (rpc) [tharsis#624](https://github.com/tharsis/ethermint/pull/624) Implement new JSON-RPC endpoints from latest geth version * (rpc) [tharsis#624](https://github.com/tharsis/ethermint/pull/624) Implement new JSON-RPC endpoints from latest geth version
* (evm) [tharsis#662](https://github.com/tharsis/ethermint/pull/662) Disable basefee for non london blocks
### Bug Fixes ### Bug Fixes

View File

@ -359,7 +359,7 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
} }
var baseFee *big.Int var baseFee *big.Int
if !feeMktParams.NoBaseFee { if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) && !feeMktParams.NoBaseFee {
baseFee = ctd.feemarketKeeper.GetBaseFee(ctx) baseFee = ctd.feemarketKeeper.GetBaseFee(ctx)
} }
@ -383,14 +383,14 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
) )
} }
if !feeMktParams.NoBaseFee && baseFee == nil { if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) && !feeMktParams.NoBaseFee && baseFee == nil {
return ctx, stacktrace.Propagate( return ctx, stacktrace.Propagate(
sdkerrors.Wrap(evmtypes.ErrInvalidBaseFee, "base fee is supported but evm block context value is nil"), sdkerrors.Wrap(evmtypes.ErrInvalidBaseFee, "base fee is supported but evm block context value is nil"),
"address %s", coreMsg.From(), "address %s", coreMsg.From(),
) )
} }
if !feeMktParams.NoBaseFee && baseFee != nil && coreMsg.GasFeeCap().Cmp(baseFee) < 0 { if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) && !feeMktParams.NoBaseFee && baseFee != nil && coreMsg.GasFeeCap().Cmp(baseFee) < 0 {
return ctx, stacktrace.Propagate( return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(evmtypes.ErrInvalidBaseFee, "max fee per gas less than block base fee (%s < %s)", coreMsg.GasFeeCap(), baseFee), sdkerrors.Wrapf(evmtypes.ErrInvalidBaseFee, "max fee per gas less than block base fee (%s < %s)", coreMsg.GasFeeCap(), baseFee),
"address %s", coreMsg.From(), "address %s", coreMsg.From(),

View File

@ -62,7 +62,7 @@ type Backend interface {
GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error) GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error)
GetTxByEthHash(txHash common.Hash) (*tmrpctypes.ResultTx, error) GetTxByEthHash(txHash common.Hash) (*tmrpctypes.ResultTx, error)
EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error)
BaseFee() (*big.Int, error) BaseFee(height int64) (*big.Int, error)
// Filter API // Filter API
BloomStatus() (uint64, uint64) BloomStatus() (uint64, uint64)
@ -238,7 +238,7 @@ func (e *EVMBackend) EthBlockFromTendermint(
ctx := types.ContextWithHeight(block.Height) ctx := types.ContextWithHeight(block.Height)
baseFee, err := e.BaseFee() baseFee, err := e.BaseFee(block.Height)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -370,7 +370,7 @@ func (e *EVMBackend) HeaderByNumber(blockNum types.BlockNumber) (*ethtypes.Heade
e.logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Block.Height) e.logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Block.Height)
} }
baseFee, err := e.BaseFee() baseFee, err := e.BaseFee(resBlock.Block.Height)
if err != nil { if err != nil {
e.logger.Debug("HeaderByNumber BaseFee failed", "height", resBlock.Block.Height, "error", err.Error()) e.logger.Debug("HeaderByNumber BaseFee failed", "height", resBlock.Block.Height, "error", err.Error())
return nil, err return nil, err
@ -398,7 +398,7 @@ func (e *EVMBackend) HeaderByHash(blockHash common.Hash) (*ethtypes.Header, erro
e.logger.Debug("HeaderByHash BlockBloom failed", "height", resBlock.Block.Height) e.logger.Debug("HeaderByHash BlockBloom failed", "height", resBlock.Block.Height)
} }
baseFee, err := e.BaseFee() baseFee, err := e.BaseFee(resBlock.Block.Height)
if err != nil { if err != nil {
e.logger.Debug("HeaderByHash BaseFee failed", "height", resBlock.Block.Height, "error", err.Error()) e.logger.Debug("HeaderByHash BaseFee failed", "height", resBlock.Block.Height, "error", err.Error())
return nil, err return nil, err
@ -710,7 +710,21 @@ func (e *EVMBackend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional
return 0, err return 0, err
} }
baseFee, err := e.BaseFee() height := blockNr.Int64()
currentBlockNumber, _ := e.BlockNumber()
switch blockNr {
case types.EthLatestBlockNumber:
if currentBlockNumber > 0 {
height = int64(currentBlockNumber)
}
case types.EthPendingBlockNumber:
if currentBlockNumber > 0 {
height = int64(currentBlockNumber)
}
case types.EthEarliestBlockNumber:
height = 1
}
baseFee, err := e.BaseFee(height)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -730,7 +744,7 @@ func (e *EVMBackend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional
// From ContextWithHeight: if the provided height is 0, // From ContextWithHeight: if the provided height is 0,
// it will return an empty context and the gRPC query will use // it will return an empty context and the gRPC query will use
// the latest block height for querying. // the latest block height for querying.
res, err := e.queryClient.EstimateGas(types.ContextWithHeight(blockNr.Int64()), &req) res, err := e.queryClient.EstimateGas(types.ContextWithHeight(height), &req)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -805,9 +819,14 @@ func (e *EVMBackend) SuggestGasTipCap() (*big.Int, error) {
} }
// BaseFee returns the base fee tracked by the Fee Market module. If the base fee is not enabled, // BaseFee returns the base fee tracked by the Fee Market module. If the base fee is not enabled,
// it returns the initial base fee amount. // it returns the initial base fee amount. Return nil if London is not activated.
func (e *EVMBackend) BaseFee() (*big.Int, error) { func (e *EVMBackend) BaseFee(height int64) (*big.Int, error) {
res, err := e.queryClient.FeeMarket.BaseFee(e.ctx, &feemarkettypes.QueryBaseFeeRequest{}) cfg := e.ChainConfig()
if !cfg.IsLondon(new(big.Int).SetInt64(height)) {
return nil, nil
}
res, err := e.queryClient.FeeMarket.BaseFee(types.ContextWithHeight(height), &feemarkettypes.QueryBaseFeeRequest{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -816,7 +835,7 @@ func (e *EVMBackend) BaseFee() (*big.Int, error) {
return res.BaseFee.BigInt(), nil return res.BaseFee.BigInt(), nil
} }
resParams, err := e.queryClient.FeeMarket.Params(e.ctx, &feemarkettypes.QueryParamsRequest{}) resParams, err := e.queryClient.FeeMarket.Params(types.ContextWithHeight(height), &feemarkettypes.QueryParamsRequest{})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -587,7 +587,21 @@ func (e *PublicAPI) doCall(
return nil, err return nil, err
} }
baseFee, err := e.backend.BaseFee() currentBlockNumber, _ := e.BlockNumber()
height := blockNr.Int64()
switch blockNr {
case rpctypes.EthLatestBlockNumber:
if currentBlockNumber > 0 {
height = int64(currentBlockNumber)
}
case rpctypes.EthPendingBlockNumber:
if currentBlockNumber > 0 {
height = int64(currentBlockNumber)
}
case rpctypes.EthEarliestBlockNumber:
height = 1
}
baseFee, err := e.backend.BaseFee(height)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -680,7 +694,7 @@ func (e *PublicAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexu
return nil, err return nil, err
} }
baseFee, err := e.backend.BaseFee() baseFee, err := e.backend.BaseFee(resBlock.Block.Height)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -159,7 +159,10 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT
// get the latest signer according to the chain rules from the config // get the latest signer according to the chain rules from the config
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight())) signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight()))
baseFee := k.feeMarketKeeper.GetBaseFee(ctx) var baseFee *big.Int
if types.IsLondon(ethCfg, ctx.BlockHeight()) {
baseFee = k.feeMarketKeeper.GetBaseFee(ctx)
}
msg, err := tx.AsMessage(signer, baseFee) msg, err := tx.AsMessage(signer, baseFee)
if err != nil { if err != nil {
@ -368,7 +371,10 @@ func (k *Keeper) ApplyNativeMessage(msg core.Message) (*types.MsgEthereumTxRespo
return nil, stacktrace.Propagate(err, "failed to obtain coinbase address") return nil, stacktrace.Propagate(err, "failed to obtain coinbase address")
} }
baseFee := k.feeMarketKeeper.GetBaseFee(ctx) var baseFee *big.Int
if types.IsLondon(ethCfg, ctx.BlockHeight()) {
baseFee = k.feeMarketKeeper.GetBaseFee(ctx)
}
tracer := types.NewTracer(k.tracer, msg, ethCfg, ctx.BlockHeight(), k.debug) tracer := types.NewTracer(k.tracer, msg, ethCfg, ctx.BlockHeight(), k.debug)
evm := k.NewEVM(msg, ethCfg, params, coinbase, baseFee, tracer) evm := k.NewEVM(msg, ethCfg, params, coinbase, baseFee, tracer)

View File

@ -2,6 +2,9 @@ package types
import ( import (
"fmt" "fmt"
"math/big"
"github.com/ethereum/go-ethereum/params"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
@ -132,3 +135,8 @@ func validateChainConfig(i interface{}) error {
return cfg.Validate() return cfg.Validate()
} }
func IsLondon(ethConfig *params.ChainConfig, height int64) bool {
rules := ethConfig.Rules(big.NewInt(height))
return rules.IsLondon
}

View File

@ -3,6 +3,8 @@ package types
import ( import (
"testing" "testing"
"github.com/ethereum/go-ethereum/params"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -104,3 +106,32 @@ func TestValidateChainConfig(t *testing.T) {
} }
} }
} }
func TestIsLondon(t *testing.T) {
testCases := []struct {
name string
height int64
result bool
}{
{
"Before london block",
5,
false,
},
{
"After london block",
12_965_001,
true,
},
{
"london block",
12_965_000,
true,
},
}
for _, tc := range testCases {
ethConfig := params.MainnetChainConfig
require.Equal(t, IsLondon(ethConfig, tc.height), tc.result)
}
}