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
* (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

View File

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

View File

@ -62,7 +62,7 @@ type Backend interface {
GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error)
GetTxByEthHash(txHash common.Hash) (*tmrpctypes.ResultTx, error)
EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error)
BaseFee() (*big.Int, error)
BaseFee(height int64) (*big.Int, error)
// Filter API
BloomStatus() (uint64, uint64)
@ -238,7 +238,7 @@ func (e *EVMBackend) EthBlockFromTendermint(
ctx := types.ContextWithHeight(block.Height)
baseFee, err := e.BaseFee()
baseFee, err := e.BaseFee(block.Height)
if err != nil {
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)
}
baseFee, err := e.BaseFee()
baseFee, err := e.BaseFee(resBlock.Block.Height)
if err != nil {
e.logger.Debug("HeaderByNumber BaseFee failed", "height", resBlock.Block.Height, "error", err.Error())
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)
}
baseFee, err := e.BaseFee()
baseFee, err := e.BaseFee(resBlock.Block.Height)
if err != nil {
e.logger.Debug("HeaderByHash BaseFee failed", "height", resBlock.Block.Height, "error", err.Error())
return nil, err
@ -710,7 +710,21 @@ func (e *EVMBackend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional
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 {
return 0, err
}
@ -730,7 +744,7 @@ func (e *EVMBackend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional
// From ContextWithHeight: if the provided height is 0,
// it will return an empty context and the gRPC query will use
// 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 {
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,
// it returns the initial base fee amount.
func (e *EVMBackend) BaseFee() (*big.Int, error) {
res, err := e.queryClient.FeeMarket.BaseFee(e.ctx, &feemarkettypes.QueryBaseFeeRequest{})
// it returns the initial base fee amount. Return nil if London is not activated.
func (e *EVMBackend) BaseFee(height int64) (*big.Int, error) {
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 {
return nil, err
}
@ -816,7 +835,7 @@ func (e *EVMBackend) BaseFee() (*big.Int, error) {
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 {
return nil, err
}

View File

@ -587,7 +587,21 @@ func (e *PublicAPI) doCall(
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 {
return nil, err
}
@ -680,7 +694,7 @@ func (e *PublicAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexu
return nil, err
}
baseFee, err := e.backend.BaseFee()
baseFee, err := e.backend.BaseFee(resBlock.Block.Height)
if err != nil {
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
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)
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")
}
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)
evm := k.NewEVM(msg, ethCfg, params, coinbase, baseFee, tracer)

View File

@ -2,6 +2,9 @@ package types
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/params"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
@ -132,3 +135,8 @@ func validateChainConfig(i interface{}) error {
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 (
"testing"
"github.com/ethereum/go-ethereum/params"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"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)
}
}