diff --git a/CHANGELOG.md b/CHANGELOG.md index 716bcd84f5..016284bd55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -131,6 +131,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (analytics) [#1434](https://github.com/evmos/ethermint/pull/1434) Remove unbound labels from custom tendermint metrics. * (rpc) [#1484](https://github.com/evmos/ethermint/pull/1484) Align empty account result for old blocks as ethereum instead of return account not found error. * (rpc) [#1503](https://github.com/evmos/ethermint/pull/1503) Fix block hashes returned on JSON-RPC filter `eth_newBlockFilter`. +* (rpc) [#1557](https://github.com/evmos/ethermint/pull/1557) Patch GasUsed before the fix of revert gas refund logic when transaction reverted for `eth_getTransactionReceipt`. * (ante) [#1566](https://github.com/evmos/ethermint/pull/1566) Fix `gasWanted` on `EthGasConsumeDecorator` ante handler when running transaction in `ReCheckMode` ## [v0.19.3] - 2022-10-14 diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 687b4c1617..317ed976b2 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -17,6 +17,7 @@ package backend import ( "fmt" + "math/big" errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -131,6 +132,17 @@ func (b *Backend) getTransactionByHashPending(txHash common.Hash) (*rpctypes.RPC return nil, nil } +// GetGasUsed returns gasUsed from transaction +func (b *Backend) GetGasUsed(res *ethermint.TxResult, price *big.Int, gas uint64) uint64 { + // patch gasUsed if tx is reverted and happened before height on which fixed was introduced + // to return real gas charged + // more info at https://github.com/evmos/ethermint/pull/1557 + if res.Failed && res.Height < b.cfg.JSONRPC.FixRevertGasRefundHeight { + return new(big.Int).Mul(price, new(big.Int).SetUint64(gas)).Uint64() + } + return res.GasUsed +} + // GetTransactionReceipt returns the transaction receipt identified by hash. func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) { hexTx := hash.Hex() @@ -141,7 +153,6 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ b.logger.Debug("tx not found", "hash", hexTx, "error", err.Error()) return nil, nil } - resBlock, err := b.TendermintBlockByNumber(rpctypes.BlockNumber(res.Height)) if err != nil { b.logger.Debug("block not found", "height", res.Height, "error", err.Error()) @@ -177,7 +188,6 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ } else { status = hexutil.Uint(ethtypes.ReceiptStatusSuccessful) } - chainID, err := b.ChainID() if err != nil { return nil, err @@ -220,7 +230,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ // They are stored in the chain database. "transactionHash": hash, "contractAddress": nil, - "gasUsed": hexutil.Uint64(res.GasUsed), + "gasUsed": hexutil.Uint64(b.GetGasUsed(res, txData.GetGasPrice(), txData.GetGas())), // Inclusion information: These fields provide information about the inclusion of the // transaction corresponding to this receipt. diff --git a/rpc/backend/tx_info_test.go b/rpc/backend/tx_info_test.go index bb2649657a..904686fb1d 100644 --- a/rpc/backend/tx_info_test.go +++ b/rpc/backend/tx_info_test.go @@ -598,3 +598,59 @@ func (suite *BackendTestSuite) TestGetTransactionReceipt() { }) } } + +func (suite *BackendTestSuite) TestGetGasUsed() { + origin := suite.backend.cfg.JSONRPC.FixRevertGasRefundHeight + testCases := []struct { + name string + fixRevertGasRefundHeight int64 + txResult *ethermint.TxResult + price *big.Int + gas uint64 + exp uint64 + }{ + { + "success txResult", + 1, + ðermint.TxResult{ + Height: 1, + Failed: false, + GasUsed: 53026, + }, + new(big.Int).SetUint64(0), + 0, + 53026, + }, + { + "fail txResult before cap", + 2, + ðermint.TxResult{ + Height: 1, + Failed: true, + GasUsed: 53026, + }, + new(big.Int).SetUint64(200000), + 5000000000000, + 1000000000000000000, + }, + { + "fail txResult after cap", + 2, + ðermint.TxResult{ + Height: 3, + Failed: true, + GasUsed: 53026, + }, + new(big.Int).SetUint64(200000), + 5000000000000, + 53026, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.backend.cfg.JSONRPC.FixRevertGasRefundHeight = tc.fixRevertGasRefundHeight + suite.Require().Equal(tc.exp, suite.backend.GetGasUsed(tc.txResult, tc.price, tc.gas)) + suite.backend.cfg.JSONRPC.FixRevertGasRefundHeight = origin + }) + } +} diff --git a/server/config/config.go b/server/config/config.go index 760bd9aaaa..ed897ee8b7 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -46,6 +46,9 @@ const ( // DefaultEVMTracer is the default vm.Tracer type DefaultEVMTracer = "" + // DefaultFixRevertGasRefundHeight is the default height at which to overwrite gas refund + DefaultFixRevertGasRefundHeight = 0 + DefaultMaxTxGasWanted = 0 DefaultGasCap uint64 = 25000000 @@ -59,14 +62,17 @@ const ( DefaultBlockRangeCap int32 = 10000 DefaultEVMTimeout = 5 * time.Second + // default 1.0 eth DefaultTxFeeCap float64 = 1.0 DefaultHTTPTimeout = 30 * time.Second DefaultHTTPIdleTimeout = 120 * time.Second + // DefaultAllowUnprotectedTxs value is false DefaultAllowUnprotectedTxs = false + // DefaultMaxOpenConnections represents the amount of open connections (unlimited = 0) DefaultMaxOpenConnections = 0 ) @@ -130,6 +136,8 @@ type JSONRPCConfig struct { EnableIndexer bool `mapstructure:"enable-indexer"` // MetricsAddress defines the metrics server to listen on MetricsAddress string `mapstructure:"metrics-address"` + // FixRevertGasRefundHeight defines the upgrade height for fix of revert gas refund logic when transaction reverted + FixRevertGasRefundHeight int64 `mapstructure:"fix-revert-gas-refund-height"` } // TLSConfig defines the certificate and matching private key for the server. @@ -215,23 +223,24 @@ func GetAPINamespaces() []string { // DefaultJSONRPCConfig returns an EVM config with the JSON-RPC API enabled by default func DefaultJSONRPCConfig() *JSONRPCConfig { return &JSONRPCConfig{ - Enable: true, - API: GetDefaultAPINamespaces(), - Address: DefaultJSONRPCAddress, - WsAddress: DefaultJSONRPCWsAddress, - GasCap: DefaultGasCap, - EVMTimeout: DefaultEVMTimeout, - TxFeeCap: DefaultTxFeeCap, - FilterCap: DefaultFilterCap, - FeeHistoryCap: DefaultFeeHistoryCap, - BlockRangeCap: DefaultBlockRangeCap, - LogsCap: DefaultLogsCap, - HTTPTimeout: DefaultHTTPTimeout, - HTTPIdleTimeout: DefaultHTTPIdleTimeout, - AllowUnprotectedTxs: DefaultAllowUnprotectedTxs, - MaxOpenConnections: DefaultMaxOpenConnections, - EnableIndexer: false, - MetricsAddress: DefaultJSONRPCMetricsAddress, + Enable: true, + API: GetDefaultAPINamespaces(), + Address: DefaultJSONRPCAddress, + WsAddress: DefaultJSONRPCWsAddress, + GasCap: DefaultGasCap, + EVMTimeout: DefaultEVMTimeout, + TxFeeCap: DefaultTxFeeCap, + FilterCap: DefaultFilterCap, + FeeHistoryCap: DefaultFeeHistoryCap, + BlockRangeCap: DefaultBlockRangeCap, + LogsCap: DefaultLogsCap, + HTTPTimeout: DefaultHTTPTimeout, + HTTPIdleTimeout: DefaultHTTPIdleTimeout, + AllowUnprotectedTxs: DefaultAllowUnprotectedTxs, + MaxOpenConnections: DefaultMaxOpenConnections, + EnableIndexer: false, + MetricsAddress: DefaultJSONRPCMetricsAddress, + FixRevertGasRefundHeight: DefaultFixRevertGasRefundHeight, } } @@ -325,22 +334,23 @@ func GetConfig(v *viper.Viper) (Config, error) { MaxTxGasWanted: v.GetUint64("evm.max-tx-gas-wanted"), }, JSONRPC: JSONRPCConfig{ - Enable: v.GetBool("json-rpc.enable"), - API: v.GetStringSlice("json-rpc.api"), - Address: v.GetString("json-rpc.address"), - WsAddress: v.GetString("json-rpc.ws-address"), - GasCap: v.GetUint64("json-rpc.gas-cap"), - FilterCap: v.GetInt32("json-rpc.filter-cap"), - FeeHistoryCap: v.GetInt32("json-rpc.feehistory-cap"), - TxFeeCap: v.GetFloat64("json-rpc.txfee-cap"), - EVMTimeout: v.GetDuration("json-rpc.evm-timeout"), - LogsCap: v.GetInt32("json-rpc.logs-cap"), - BlockRangeCap: v.GetInt32("json-rpc.block-range-cap"), - HTTPTimeout: v.GetDuration("json-rpc.http-timeout"), - HTTPIdleTimeout: v.GetDuration("json-rpc.http-idle-timeout"), - MaxOpenConnections: v.GetInt("json-rpc.max-open-connections"), - EnableIndexer: v.GetBool("json-rpc.enable-indexer"), - MetricsAddress: v.GetString("json-rpc.metrics-address"), + Enable: v.GetBool("json-rpc.enable"), + API: v.GetStringSlice("json-rpc.api"), + Address: v.GetString("json-rpc.address"), + WsAddress: v.GetString("json-rpc.ws-address"), + GasCap: v.GetUint64("json-rpc.gas-cap"), + FilterCap: v.GetInt32("json-rpc.filter-cap"), + FeeHistoryCap: v.GetInt32("json-rpc.feehistory-cap"), + TxFeeCap: v.GetFloat64("json-rpc.txfee-cap"), + EVMTimeout: v.GetDuration("json-rpc.evm-timeout"), + LogsCap: v.GetInt32("json-rpc.logs-cap"), + BlockRangeCap: v.GetInt32("json-rpc.block-range-cap"), + HTTPTimeout: v.GetDuration("json-rpc.http-timeout"), + HTTPIdleTimeout: v.GetDuration("json-rpc.http-idle-timeout"), + MaxOpenConnections: v.GetInt("json-rpc.max-open-connections"), + EnableIndexer: v.GetBool("json-rpc.enable-indexer"), + MetricsAddress: v.GetString("json-rpc.metrics-address"), + FixRevertGasRefundHeight: v.GetInt64("json-rpc.fix-revert-gas-refund-height"), }, TLS: TLSConfig{ CertificatePath: v.GetString("tls.certificate-path"), diff --git a/server/config/toml.go b/server/config/toml.go index 89abb9badc..a61f110dc7 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -92,6 +92,9 @@ enable-indexer = {{ .JSONRPC.EnableIndexer }} # Prometheus metrics path: /debug/metrics/prometheus metrics-address = "{{ .JSONRPC.MetricsAddress }}" +# Upgrade height for fix of revert gas refund logic when transaction reverted. +fix-revert-gas-refund-height = {{ .JSONRPC.FixRevertGasRefundHeight }} + ############################################################################### ### TLS Configuration ### ############################################################################### diff --git a/server/flags/flags.go b/server/flags/flags.go index 6613ef4ceb..5f3d9c7112 100644 --- a/server/flags/flags.go +++ b/server/flags/flags.go @@ -68,7 +68,8 @@ const ( // JSONRPCEnableMetrics enables EVM RPC metrics server. // Set to `metrics` which is hardcoded flag from go-ethereum. // https://github.com/ethereum/go-ethereum/blob/master/metrics/metrics.go#L35-L55 - JSONRPCEnableMetrics = "metrics" + JSONRPCEnableMetrics = "metrics" + JSONRPCFixRevertGasRefundHeight = "json-rpc.fix-revert-gas-refund-height" ) // EVM flags diff --git a/tests/integration_tests/configs/default.jsonnet b/tests/integration_tests/configs/default.jsonnet index b181297d5b..349be756f4 100644 --- a/tests/integration_tests/configs/default.jsonnet +++ b/tests/integration_tests/configs/default.jsonnet @@ -19,6 +19,7 @@ 'feehistory-cap': 100, 'block-range-cap': 10000, 'logs-cap': 10000, + 'fix-revert-gas-refund-height': 1, }, }, validators: [{