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.
|
* (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
|
||||||
|
|
||||||
|
@ -222,14 +222,12 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
|||||||
// 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,13 +475,11 @@ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -491,27 +487,21 @@ func NewEthMempoolFeeDecorator(ek EVMKeeper, fmk evmtypes.FeeMarketKeeper) EthMe
|
|||||||
// 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 {
|
||||||
|
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() {
|
for _, msg := range tx.GetMsgs() {
|
||||||
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
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
|
evmDenom := params.EvmDenom
|
||||||
baseFee := mfd.evmKeeper.BaseFee(ctx, ethCfg)
|
feeAmt := ethMsg.GetFee()
|
||||||
if baseFee != nil {
|
|
||||||
feeAmt = ethMsg.GetEffectiveFee(baseFee)
|
|
||||||
} else {
|
|
||||||
feeAmt = ethMsg.GetFee()
|
|
||||||
}
|
|
||||||
|
|
||||||
glDec := sdk.NewDec(int64(ethMsg.GetGas()))
|
glDec := sdk.NewDec(int64(ethMsg.GetGas()))
|
||||||
requiredFee := ctx.MinGasPrices().AmountOf(evmDenom).Mul(glDec)
|
requiredFee := ctx.MinGasPrices().AmountOf(evmDenom).Mul(glDec)
|
||||||
if sdk.NewDecFromBigInt(feeAmt).LT(requiredFee) {
|
if sdk.NewDecFromBigInt(feeAmt).LT(requiredFee) {
|
||||||
@ -519,6 +509,7 @@ func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return next(ctx, tx, simulate)
|
return next(ctx, tx, simulate)
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -49,12 +49,12 @@ 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.
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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 (
|
||||||
|
result *big.Int
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if head := e.backend.CurrentHeader(); head.BaseFee != nil {
|
||||||
|
result, err = e.backend.SuggestGasTipCap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if head := e.backend.CurrentHeader(); head.BaseFee != nil {
|
result = result.Add(result, head.BaseFee)
|
||||||
tipcap.Add(tipcap, 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.
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user