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:
parent
e39a74998e
commit
724a06632b
@ -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.
|
||||
* (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
|
||||
|
||||
|
@ -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
|
||||
// context rules.
|
||||
type CanTransferDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
feemarketKeeper evmtypes.FeeMarketKeeper
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewCanTransferDecorator creates a new CanTransferDecorator instance.
|
||||
func NewCanTransferDecorator(evmKeeper EVMKeeper, fmk evmtypes.FeeMarketKeeper) CanTransferDecorator {
|
||||
func NewCanTransferDecorator(evmKeeper EVMKeeper) CanTransferDecorator {
|
||||
return CanTransferDecorator{
|
||||
evmKeeper: evmKeeper,
|
||||
feemarketKeeper: fmk,
|
||||
evmKeeper: evmKeeper,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator
|
||||
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{
|
||||
feemarketKeeper: fmk,
|
||||
evmKeeper: ek,
|
||||
evmKeeper: ek,
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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) {
|
||||
if ctx.IsCheckTx() && !simulate {
|
||||
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))
|
||||
}
|
||||
params := mfd.evmKeeper.GetParams(ctx)
|
||||
ethCfg := params.ChainConfig.EthereumConfig(mfd.evmKeeper.ChainID())
|
||||
baseFee := mfd.evmKeeper.BaseFee(ctx, ethCfg)
|
||||
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
|
||||
|
||||
params := mfd.evmKeeper.GetParams(ctx)
|
||||
chainID := mfd.evmKeeper.ChainID()
|
||||
ethCfg := params.ChainConfig.EthereumConfig(chainID)
|
||||
evmDenom := params.EvmDenom
|
||||
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)
|
||||
evmDenom := params.EvmDenom
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,7 +293,7 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestCanTransferDecorator() {
|
||||
dec := ante.NewCanTransferDecorator(suite.app.EvmKeeper, suite.app.FeeMarketKeeper)
|
||||
dec := ante.NewCanTransferDecorator(suite.app.EvmKeeper)
|
||||
|
||||
addr, privKey := tests.NewAddrKey()
|
||||
|
||||
|
@ -48,13 +48,13 @@ func (options HandlerOptions) Validate() error {
|
||||
|
||||
func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler {
|
||||
return sdk.ChainAnteDecorators(
|
||||
NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first
|
||||
NewEthMempoolFeeDecorator(options.EvmKeeper, options.FeeMarketKeeper), // Check eth effective gas price against minimal-gas-prices
|
||||
NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first
|
||||
NewEthMempoolFeeDecorator(options.EvmKeeper), // Check eth effective gas price against minimal-gas-prices
|
||||
NewEthValidateBasicDecorator(options.EvmKeeper),
|
||||
NewEthSigVerificationDecorator(options.EvmKeeper),
|
||||
NewEthAccountVerificationDecorator(options.AccountKeeper, options.BankKeeper, options.EvmKeeper),
|
||||
NewEthGasConsumeDecorator(options.EvmKeeper),
|
||||
NewCanTransferDecorator(options.EvmKeeper, options.FeeMarketKeeper),
|
||||
NewCanTransferDecorator(options.EvmKeeper),
|
||||
NewEthIncrementSenderSequenceDecorator(options.AccountKeeper), // innermost AnteDecorator.
|
||||
)
|
||||
}
|
||||
|
@ -10,10 +10,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
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/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
@ -802,23 +800,6 @@ func (e *EVMBackend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash
|
||||
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
|
||||
res, err := e.queryClient.QueryClient.Params(e.ctx, &evmtypes.QueryParamsRequest{})
|
||||
if err != nil {
|
||||
@ -826,19 +807,16 @@ func (e *EVMBackend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
txEncoder := e.clientCtx.TxConfig.TxEncoder()
|
||||
txBytes, err := txEncoder(builder.GetTx())
|
||||
txBytes, err := txEncoder(tx)
|
||||
if err != nil {
|
||||
e.logger.Error("failed to encode eth tx using default encoder", "error", err.Error())
|
||||
return common.Hash{}, err
|
||||
@ -976,9 +954,9 @@ func (e *EVMBackend) ChainConfig() *params.ChainConfig {
|
||||
}
|
||||
|
||||
// SuggestGasTipCap returns the suggested tip cap
|
||||
// always return zero since we don't support tx prioritization yet.
|
||||
func (e *EVMBackend) SuggestGasTipCap() (*big.Int, error) {
|
||||
out := new(big.Int).SetInt64(e.RPCMinGasPrice())
|
||||
return out, nil
|
||||
return big.NewInt(0), nil
|
||||
}
|
||||
|
||||
// BaseFee returns the base fee tracked by the Fee Market module. If the base fee is not enabled,
|
||||
|
@ -193,16 +193,22 @@ func (e *PublicAPI) Hashrate() hexutil.Uint64 {
|
||||
// GasPrice returns the current gas price based on Ethermint's gas price oracle.
|
||||
func (e *PublicAPI) GasPrice() (*hexutil.Big, error) {
|
||||
e.logger.Debug("eth_gasPrice")
|
||||
tipcap, err := e.backend.SuggestGasTipCap()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
result *big.Int
|
||||
err error
|
||||
)
|
||||
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.
|
||||
|
@ -66,6 +66,11 @@ func (k Keeper) DeductTxCostsFromUserBalance(
|
||||
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))}
|
||||
|
||||
// deduct the full gas cost from the user balance
|
||||
|
@ -330,11 +330,10 @@ func (msg *MsgEthereumTx) BuildTx(b client.TxBuilder, evmDenom string) (signing.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fees := sdk.Coins{
|
||||
{
|
||||
Denom: evmDenom,
|
||||
Amount: sdk.NewIntFromBigInt(txData.Fee()),
|
||||
},
|
||||
fees := make(sdk.Coins, 0)
|
||||
feeAmt := sdk.NewIntFromBigInt(txData.Fee())
|
||||
if feeAmt.Sign() > 0 {
|
||||
fees = append(fees, sdk.NewCoin(evmDenom, feeAmt))
|
||||
}
|
||||
|
||||
builder.SetExtensionOptions(option)
|
||||
|
Loading…
Reference in New Issue
Block a user