fix: minimal-gas-prices and baseFeePerGas conflicts (#916)

* Problem: minimal-gas-prices and baseFeePerGas conflicts

Closes: #915

Solution:
- Don't check min-gas-price for evm tx if london hardfork and feemarket enabled.

comments and cleanup

changelog

* fix zero fee coins

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
yihuang 2022-01-26 18:44:41 +08:00 committed by GitHub
parent e39a74998e
commit 724a06632b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 56 additions and 76 deletions

View File

@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (ante) [\#866](https://github.com/tharsis/ethermint/pull/866) `NewAnteHandler` constructor now receives a `HandlerOptions` field. * (ante) [\#866](https://github.com/tharsis/ethermint/pull/866) `NewAnteHandler` constructor now receives a `HandlerOptions` field.
* (evm) [\#849](https://github.com/tharsis/ethermint/pull/849) `PostTxProcessing` hook now takes an Ethereum tx `Receipt` and a `from` `Address` as arguments. * (evm) [\#849](https://github.com/tharsis/ethermint/pull/849) `PostTxProcessing` hook now takes an Ethereum tx `Receipt` and a `from` `Address` as arguments.
* (ante) [#916](https://github.com/tharsis/ethermint/pull/916) don't check min-gas-price for eth tx if london hardfork enabled and feemarket enabled.
### State Machine Breaking ### State Machine Breaking

View File

@ -221,15 +221,13 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
// CanTransferDecorator checks if the sender is allowed to transfer funds according to the EVM block // CanTransferDecorator checks if the sender is allowed to transfer funds according to the EVM block
// context rules. // context rules.
type CanTransferDecorator struct { type CanTransferDecorator struct {
evmKeeper EVMKeeper evmKeeper EVMKeeper
feemarketKeeper evmtypes.FeeMarketKeeper
} }
// NewCanTransferDecorator creates a new CanTransferDecorator instance. // NewCanTransferDecorator creates a new CanTransferDecorator instance.
func NewCanTransferDecorator(evmKeeper EVMKeeper, fmk evmtypes.FeeMarketKeeper) CanTransferDecorator { func NewCanTransferDecorator(evmKeeper EVMKeeper) CanTransferDecorator {
return CanTransferDecorator{ return CanTransferDecorator{
evmKeeper: evmKeeper, evmKeeper: evmKeeper,
feemarketKeeper: fmk,
} }
} }
@ -477,45 +475,38 @@ func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
// If fee is high enough or not CheckTx, then call next AnteHandler // If fee is high enough or not CheckTx, then call next AnteHandler
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator // CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator
type EthMempoolFeeDecorator struct { type EthMempoolFeeDecorator struct {
feemarketKeeper evmtypes.FeeMarketKeeper evmKeeper EVMKeeper
evmKeeper EVMKeeper
} }
func NewEthMempoolFeeDecorator(ek EVMKeeper, fmk evmtypes.FeeMarketKeeper) EthMempoolFeeDecorator { func NewEthMempoolFeeDecorator(ek EVMKeeper) EthMempoolFeeDecorator {
return EthMempoolFeeDecorator{ return EthMempoolFeeDecorator{
feemarketKeeper: fmk, evmKeeper: ek,
evmKeeper: ek,
} }
} }
// AnteHandle ensures that the provided fees meet a minimum threshold for the validator, // AnteHandle ensures that the provided fees meet a minimum threshold for the validator,
// if this is a CheckTx. This is only for local mempool purposes, and thus // if this is a CheckTx. This is only for local mempool purposes, and thus
// is only ran on check tx. // is only ran on check tx.
// It only do the check if london hardfork not enabled or feemarket not enabled, because in that case feemarket will take over the task.
func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if ctx.IsCheckTx() && !simulate { if ctx.IsCheckTx() && !simulate {
for _, msg := range tx.GetMsgs() { params := mfd.evmKeeper.GetParams(ctx)
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) ethCfg := params.ChainConfig.EthereumConfig(mfd.evmKeeper.ChainID())
if !ok { baseFee := mfd.evmKeeper.BaseFee(ctx, ethCfg)
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil)) if baseFee == nil {
} for _, msg := range tx.GetMsgs() {
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
var feeAmt *big.Int evmDenom := params.EvmDenom
feeAmt := ethMsg.GetFee()
params := mfd.evmKeeper.GetParams(ctx) glDec := sdk.NewDec(int64(ethMsg.GetGas()))
chainID := mfd.evmKeeper.ChainID() requiredFee := ctx.MinGasPrices().AmountOf(evmDenom).Mul(glDec)
ethCfg := params.ChainConfig.EthereumConfig(chainID) if sdk.NewDecFromBigInt(feeAmt).LT(requiredFee) {
evmDenom := params.EvmDenom return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeAmt, requiredFee)
baseFee := mfd.evmKeeper.BaseFee(ctx, ethCfg) }
if baseFee != nil {
feeAmt = ethMsg.GetEffectiveFee(baseFee)
} else {
feeAmt = ethMsg.GetFee()
}
glDec := sdk.NewDec(int64(ethMsg.GetGas()))
requiredFee := ctx.MinGasPrices().AmountOf(evmDenom).Mul(glDec)
if sdk.NewDecFromBigInt(feeAmt).LT(requiredFee) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeAmt, requiredFee)
} }
} }
} }

View File

@ -293,7 +293,7 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
} }
func (suite AnteTestSuite) TestCanTransferDecorator() { func (suite AnteTestSuite) TestCanTransferDecorator() {
dec := ante.NewCanTransferDecorator(suite.app.EvmKeeper, suite.app.FeeMarketKeeper) dec := ante.NewCanTransferDecorator(suite.app.EvmKeeper)
addr, privKey := tests.NewAddrKey() addr, privKey := tests.NewAddrKey()

View File

@ -48,13 +48,13 @@ func (options HandlerOptions) Validate() error {
func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler { func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler {
return sdk.ChainAnteDecorators( return sdk.ChainAnteDecorators(
NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first
NewEthMempoolFeeDecorator(options.EvmKeeper, options.FeeMarketKeeper), // Check eth effective gas price against minimal-gas-prices NewEthMempoolFeeDecorator(options.EvmKeeper), // Check eth effective gas price against minimal-gas-prices
NewEthValidateBasicDecorator(options.EvmKeeper), NewEthValidateBasicDecorator(options.EvmKeeper),
NewEthSigVerificationDecorator(options.EvmKeeper), NewEthSigVerificationDecorator(options.EvmKeeper),
NewEthAccountVerificationDecorator(options.AccountKeeper, options.BankKeeper, options.EvmKeeper), NewEthAccountVerificationDecorator(options.AccountKeeper, options.BankKeeper, options.EvmKeeper),
NewEthGasConsumeDecorator(options.EvmKeeper), NewEthGasConsumeDecorator(options.EvmKeeper),
NewCanTransferDecorator(options.EvmKeeper, options.FeeMarketKeeper), NewCanTransferDecorator(options.EvmKeeper),
NewEthIncrementSenderSequenceDecorator(options.AccountKeeper), // innermost AnteDecorator. NewEthIncrementSenderSequenceDecorator(options.AccountKeeper), // innermost AnteDecorator.
) )
} }

View File

@ -10,10 +10,8 @@ import (
"time" "time"
"github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/flags"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
@ -802,23 +800,6 @@ func (e *EVMBackend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash
return common.Hash{}, err return common.Hash{}, err
} }
// Assemble transaction from fields
builder, ok := e.clientCtx.TxConfig.NewTxBuilder().(authtx.ExtensionOptionsTxBuilder)
if !ok {
e.logger.Error("clientCtx.TxConfig.NewTxBuilder returns unsupported builder", "error", err.Error())
}
option, err := codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
if err != nil {
e.logger.Error("codectypes.NewAnyWithValue failed to pack an obvious value", "error", err.Error())
return common.Hash{}, err
}
builder.SetExtensionOptions(option)
if err = builder.SetMsgs(msg); err != nil {
e.logger.Error("builder.SetMsgs failed", "error", err.Error())
}
// Query params to use the EVM denomination // Query params to use the EVM denomination
res, err := e.queryClient.QueryClient.Params(e.ctx, &evmtypes.QueryParamsRequest{}) res, err := e.queryClient.QueryClient.Params(e.ctx, &evmtypes.QueryParamsRequest{})
if err != nil { if err != nil {
@ -826,19 +807,16 @@ func (e *EVMBackend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash
return common.Hash{}, err return common.Hash{}, err
} }
txData, err := evmtypes.UnpackTxData(msg.Data) // Assemble transaction from fields
tx, err := msg.BuildTx(e.clientCtx.TxConfig.NewTxBuilder(), res.Params.EvmDenom)
if err != nil { if err != nil {
e.logger.Error("failed to unpack tx data", "error", err.Error()) e.logger.Error("build cosmos tx failed", "error", err.Error())
return common.Hash{}, err return common.Hash{}, err
} }
fees := sdk.Coins{sdk.NewCoin(res.Params.EvmDenom, sdk.NewIntFromBigInt(txData.Fee()))}
builder.SetFeeAmount(fees)
builder.SetGasLimit(msg.GetGas())
// Encode transaction by default Tx encoder // Encode transaction by default Tx encoder
txEncoder := e.clientCtx.TxConfig.TxEncoder() txEncoder := e.clientCtx.TxConfig.TxEncoder()
txBytes, err := txEncoder(builder.GetTx()) txBytes, err := txEncoder(tx)
if err != nil { if err != nil {
e.logger.Error("failed to encode eth tx using default encoder", "error", err.Error()) e.logger.Error("failed to encode eth tx using default encoder", "error", err.Error())
return common.Hash{}, err return common.Hash{}, err
@ -976,9 +954,9 @@ func (e *EVMBackend) ChainConfig() *params.ChainConfig {
} }
// SuggestGasTipCap returns the suggested tip cap // SuggestGasTipCap returns the suggested tip cap
// always return zero since we don't support tx prioritization yet.
func (e *EVMBackend) SuggestGasTipCap() (*big.Int, error) { func (e *EVMBackend) SuggestGasTipCap() (*big.Int, error) {
out := new(big.Int).SetInt64(e.RPCMinGasPrice()) return big.NewInt(0), nil
return out, nil
} }
// 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,

View File

@ -193,16 +193,22 @@ func (e *PublicAPI) Hashrate() hexutil.Uint64 {
// GasPrice returns the current gas price based on Ethermint's gas price oracle. // GasPrice returns the current gas price based on Ethermint's gas price oracle.
func (e *PublicAPI) GasPrice() (*hexutil.Big, error) { func (e *PublicAPI) GasPrice() (*hexutil.Big, error) {
e.logger.Debug("eth_gasPrice") e.logger.Debug("eth_gasPrice")
tipcap, err := e.backend.SuggestGasTipCap() var (
if err != nil { result *big.Int
return nil, err err error
} )
if head := e.backend.CurrentHeader(); head.BaseFee != nil { if head := e.backend.CurrentHeader(); head.BaseFee != nil {
tipcap.Add(tipcap, head.BaseFee) result, err = e.backend.SuggestGasTipCap()
if err != nil {
return nil, err
}
result = result.Add(result, head.BaseFee)
} else {
result = big.NewInt(e.backend.RPCMinGasPrice())
} }
return (*hexutil.Big)(tipcap), nil return (*hexutil.Big)(result), nil
} }
// MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions. // MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions.

View File

@ -66,6 +66,11 @@ func (k Keeper) DeductTxCostsFromUserBalance(
feeAmt = txData.Fee() feeAmt = txData.Fee()
} }
if feeAmt.Sign() == 0 {
// zero fee, no need to deduct
return sdk.NewCoins(), nil
}
fees := sdk.Coins{sdk.NewCoin(denom, sdk.NewIntFromBigInt(feeAmt))} fees := sdk.Coins{sdk.NewCoin(denom, sdk.NewIntFromBigInt(feeAmt))}
// deduct the full gas cost from the user balance // deduct the full gas cost from the user balance

View File

@ -330,11 +330,10 @@ func (msg *MsgEthereumTx) BuildTx(b client.TxBuilder, evmDenom string) (signing.
if err != nil { if err != nil {
return nil, err return nil, err
} }
fees := sdk.Coins{ fees := make(sdk.Coins, 0)
{ feeAmt := sdk.NewIntFromBigInt(txData.Fee())
Denom: evmDenom, if feeAmt.Sign() > 0 {
Amount: sdk.NewIntFromBigInt(txData.Fee()), fees = append(fees, sdk.NewCoin(evmDenom, feeAmt))
},
} }
builder.SetExtensionOptions(option) builder.SetExtensionOptions(option)