diff --git a/CHANGELOG.md b/CHANGELOG.md index a8afb291..b6e532e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (evm) [\#529](https://github.com/tharsis/ethermint/issues/529) support return value on trace tx response. +## Improvements + +- (rpc) [#968](https://github.com/tharsis/ethermint/pull/968) Add some buffer to returned gas price to provide better default UX for client. + ## [v0.10.0] - 2022-02-26 ### API Breaking diff --git a/rpc/ethereum/backend/backend.go b/rpc/ethereum/backend/backend.go index 850737dc..c3374441 100644 --- a/rpc/ethereum/backend/backend.go +++ b/rpc/ethereum/backend/backend.go @@ -50,7 +50,7 @@ type Backend interface { RPCTxFeeCap() float64 // RPCTxFeeCap is the global transaction fee(price * gaslimit) cap for send-transaction variants. The unit is ether. RPCMinGasPrice() int64 - SuggestGasTipCap() (*big.Int, error) + SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) // Blockchain API BlockNumber() (hexutil.Uint64, error) @@ -954,9 +954,34 @@ 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) { - return big.NewInt(0), nil +// Although we don't support tx prioritization yet, but we return a positive value to help client to +// mitigate the base fee changes. +func (e *EVMBackend) SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) { + if baseFee == nil { + // london hardfork not enabled or feemarket not enabeld + return big.NewInt(0), nil + } + + params, err := e.queryClient.FeeMarket.Params(e.ctx, &feemarkettypes.QueryParamsRequest{}) + if err != nil { + return nil, err + } + // calculate the maximum base fee delta in current block, assuming all block gas limit is consumed + // ``` + // GasTarget = GasLimit / ElasticityMultiplier + // Delta = BaseFee * (GasUsed - GasTarget) / GasTarget / Denominator + // ``` + // The delta is at maximum when `GasUsed` is equal to `GasLimit`, which is: + // ``` + // MaxDelta = BaseFee * (GasLimit - GasLimit / ElasticityMultiplier) / (GasLimit / ElasticityMultiplier) / Denominator + // = BaseFee * (ElasticityMultiplier - 1) / Denominator + // ``` + maxDelta := baseFee.Int64() * (int64(params.Params.ElasticityMultiplier) - 1) / int64(params.Params.BaseFeeChangeDenominator) + if maxDelta < 0 { + // impossible if the parameter validation passed. + maxDelta = 0 + } + return big.NewInt(maxDelta), nil } // BaseFee returns the base fee tracked by the Fee Market module. If the base fee is not enabled, diff --git a/rpc/ethereum/backend/utils.go b/rpc/ethereum/backend/utils.go index dc8884eb..16e129f0 100644 --- a/rpc/ethereum/backend/utils.go +++ b/rpc/ethereum/backend/utils.go @@ -31,19 +31,16 @@ func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Tran return args, errors.New("latest header is nil") } - cfg := e.ChainConfig() - // If user specifies both maxPriorityfee and maxFee, then we do not // need to consult the chain for defaults. It's definitely a London tx. if args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil { // In this clause, user left some fields unspecified. - if cfg.IsLondon(head.Number) && args.GasPrice == nil { + if head.BaseFee != nil && args.GasPrice == nil { if args.MaxPriorityFeePerGas == nil { - tip, err := e.SuggestGasTipCap() + tip, err := e.SuggestGasTipCap(head.BaseFee) if err != nil { return args, err } - args.MaxPriorityFeePerGas = (*hexutil.Big)(tip) } @@ -65,12 +62,11 @@ func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Tran } if args.GasPrice == nil { - price, err := e.SuggestGasTipCap() + price, err := e.SuggestGasTipCap(head.BaseFee) if err != nil { return args, err } - - if cfg.IsLondon(head.Number) { + if head.BaseFee != nil { // The legacy tx gas price suggestion should not add 2x base fee // because all fees are consumed, so it would result in a spiral // upwards. diff --git a/rpc/ethereum/namespaces/eth/api.go b/rpc/ethereum/namespaces/eth/api.go index 57a963ce..2cbbb247 100644 --- a/rpc/ethereum/namespaces/eth/api.go +++ b/rpc/ethereum/namespaces/eth/api.go @@ -202,11 +202,10 @@ func (e *PublicAPI) GasPrice() (*hexutil.Big, error) { err error ) if head := e.backend.CurrentHeader(); head.BaseFee != nil { - result, err = e.backend.SuggestGasTipCap() + result, err = e.backend.SuggestGasTipCap(head.BaseFee) if err != nil { return nil, err } - result = result.Add(result, head.BaseFee) } else { result = big.NewInt(e.backend.RPCMinGasPrice()) @@ -218,11 +217,11 @@ func (e *PublicAPI) GasPrice() (*hexutil.Big, error) { // MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions. func (e *PublicAPI) MaxPriorityFeePerGas() (*hexutil.Big, error) { e.logger.Debug("eth_maxPriorityFeePerGas") - tipcap, err := e.backend.SuggestGasTipCap() + head := e.backend.CurrentHeader() + tipcap, err := e.backend.SuggestGasTipCap(head.BaseFee) if err != nil { return nil, err } - return (*hexutil.Big)(tipcap), nil }