Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

rpc: configure gas cap #457

Merged
merged 5 commits into from
Aug 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ the Tracer type used to collect execution traces from the EVM transaction execut

### Improvements

* (rpc) [tharsis#457](https://github.com/tharsis/ethermint/pull/457) Configure RPC gas cap through app config.
* (evm) [tharsis#434](https://github.com/tharsis/ethermint/pull/434) Support different `Tracer` types for the EVM.
* (deps) [tharsis#427](https://github.com/tharsis/ethermint/pull/427) Bump ibc-go to [`v1.0.0`](https://github.com/cosmos/ibc-go/releases/tag/v1.0.0)
* (gRPC) [tharsis#239](https://github.com/tharsis/ethermint/pull/239) Query `ChainConfig` via gRPC.
Expand Down
14 changes: 13 additions & 1 deletion docs/api/json-rpc/running_server.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,19 @@ ethermintd start --json-rpc.enable
ethermintd start --json-rpc.api eth,txpool,personal,net,debug,web3,miner
```

### CORS
## Set a Gas Cap

`eth_call` and `eth_estimateGas` define a global gas cap over rpc for DoS protection. You can override the default gas cap value of 25,000,000 by passing a custom value when starting the node:

```bash
# set gas cap to 85M
ethermintd start --json-rpc.gas-cap 85000000000

# set gas cap to infinite (=0)
ethermintd start --json-rpc.gas-cap 0
```

## CORS

If accessing the RPC from a browser, CORS will need to be enabled with the appropriate domain set. Otherwise, JavaScript calls are limit by the same-origin policy and requests will fail:

Expand Down
15,765 changes: 7,861 additions & 7,904 deletions docs/yarn.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethereum/rpc/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const (
// GetRPCAPIs returns the list of all APIs
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, selectedAPIs []string) []rpc.API {
nonceLock := new(types.AddrLocker)
evmBackend := backend.NewEVMBackend(ctx.Logger, clientCtx)
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)

var apis []rpc.API
// remove duplicates
Expand Down
21 changes: 19 additions & 2 deletions ethereum/rpc/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/cosmos/cosmos-sdk/client/flags"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/server"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/ethereum/go-ethereum/accounts/keystore"

Expand All @@ -28,6 +29,7 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"

"github.com/tharsis/ethermint/ethereum/rpc/types"
"github.com/tharsis/ethermint/server/config"
ethermint "github.com/tharsis/ethermint/types"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)
Expand All @@ -48,6 +50,7 @@ type Backend interface {
BloomStatus() (uint64, uint64)
GetCoinbase() (sdk.AccAddress, error)
EstimateGas(args evmtypes.CallArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error)
RPCGasCap() uint64
}

var _ Backend = (*EVMBackend)(nil)
Expand All @@ -59,20 +62,28 @@ type EVMBackend struct {
queryClient *types.QueryClient // gRPC query client
logger log.Logger
chainID *big.Int
cfg config.Config
}

// NewEVMBackend creates a new EVMBackend instance
func NewEVMBackend(logger log.Logger, clientCtx client.Context) *EVMBackend {
func NewEVMBackend(ctx *server.Context, logger log.Logger, clientCtx client.Context) *EVMBackend {
chainID, err := ethermint.ParseChainID(clientCtx.ChainID)
if err != nil {
panic(err)
}

appConf, err := config.ParseConfig(ctx.Viper)
if err != nil {
panic(err)
}

return &EVMBackend{
ctx: context.Background(),
clientCtx: clientCtx,
queryClient: types.NewQueryClient(clientCtx),
logger: logger.With("module", "evm-backend"),
chainID: chainID,
cfg: *appConf,
}
}

Expand Down Expand Up @@ -547,7 +558,8 @@ func (e *EVMBackend) EstimateGas(args evmtypes.CallArgs, blockNrOptional *types.
if err != nil {
return 0, err
}
req := evmtypes.EthCallRequest{Args: bz, GasCap: ethermint.DefaultRPCGasLimit}

req := evmtypes.EthCallRequest{Args: bz, GasCap: e.RPCGasCap()}

// From ContextWithHeight: if the provided height is 0,
// it will return an empty context and the gRPC query will use
Expand Down Expand Up @@ -581,3 +593,8 @@ func (e *EVMBackend) GetTransactionCount(address common.Address, blockNum types.
n := hexutil.Uint64(nonce)
return &n, nil
}

// RPCGasCap is the global gas cap for eth-call variants.
func (e *EVMBackend) RPCGasCap() uint64 {
return e.cfg.JSONRPC.GasCap
}
7 changes: 2 additions & 5 deletions ethereum/rpc/backend/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/tharsis/ethermint/ethereum/rpc/types"
ethermint "github.com/tharsis/ethermint/types"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)

Expand All @@ -21,10 +20,8 @@ import (
func (e *EVMBackend) setTxDefaults(args types.SendTxArgs) (types.SendTxArgs, error) {

if args.GasPrice == nil {
// TODO: Change to either:
// - min gas price from context once available through server/daemon, or
// - suggest a gas price based on the previous included txs
args.GasPrice = (*hexutil.Big)(big.NewInt(ethermint.DefaultGasPrice))
// TODO: Suggest a gas price based on the previous included txs
args.GasPrice = (*hexutil.Big)(new(big.Int).SetUint64(e.RPCGasCap()))
}

if args.Nonce == nil {
Expand Down
5 changes: 2 additions & 3 deletions ethereum/rpc/namespaces/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,7 @@ 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 {
e.logger.Debug("eth_gasPrice")
// TODO: use minimum value defined in config instead of default or implement oracle
out := big.NewInt(ethermint.DefaultGasPrice)
out := new(big.Int).SetUint64(e.backend.RPCGasCap())
return (*hexutil.Big)(out)
}

Expand Down Expand Up @@ -438,7 +437,7 @@ func (e *PublicAPI) doCall(
if err != nil {
return nil, err
}
req := evmtypes.EthCallRequest{Args: bz, GasCap: ethermint.DefaultRPCGasLimit}
req := evmtypes.EthCallRequest{Args: bz, GasCap: e.backend.RPCGasCap()}

// From ContextWithHeight: if the provided height is 0,
// it will return an empty context and the gRPC query will use
Expand Down
5 changes: 3 additions & 2 deletions ethereum/rpc/namespaces/miner/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/config"
sdkconfig "github.com/cosmos/cosmos-sdk/server/config"
sdk "github.com/cosmos/cosmos-sdk/types"

authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
Expand All @@ -23,6 +23,7 @@ import (

"github.com/tharsis/ethermint/ethereum/rpc/backend"
rpctypes "github.com/tharsis/ethermint/ethereum/rpc/types"
"github.com/tharsis/ethermint/server/config"
)

// API is the miner prefixed set of APIs in the Miner JSON-RPC spec.
Expand Down Expand Up @@ -186,7 +187,7 @@ func (api *API) SetGasPrice(gasPrice hexutil.Big) bool {
c := sdk.NewDecCoin(unit, sdk.NewIntFromBigInt(gasPrice.ToInt()))

appConf.SetMinGasPrices(sdk.DecCoins{c})
config.WriteConfigFile(api.ctx.Viper.ConfigFileUsed(), appConf)
sdkconfig.WriteConfigFile(api.ctx.Viper.ConfigFileUsed(), appConf)
api.logger.Info("Your configuration file was modified. Please RESTART your node.", "gas-price", c.String())
return true
}
39 changes: 38 additions & 1 deletion server/config/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"errors"
"fmt"

"github.com/spf13/viper"
Expand All @@ -24,6 +25,8 @@ const (

// DefaultEVMTracer is the default vm.Tracer type
DefaultEVMTracer = "json"

DefaultGasCap uint64 = 25000000
)

var (
Expand Down Expand Up @@ -113,6 +116,27 @@ type JSONRPCConfig struct {
Enable bool `mapstructure:"enable"`
// EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk)
EnableUnsafeCORS bool `mapstructure:"enable-unsafe-cors"`
// GasCap is the global gas cap for eth-call variants.
GasCap uint64 `mapstructure:"gas-cap"`
}

// Validate returns an error if the JSON-RPC configuration fields are invalid.
func (c JSONRPCConfig) Validate() error {
if c.Enable && len(c.API) == 0 {
return errors.New("cannot enable JSON-RPC without defining any API namespace")
}

// TODO: validate APIs
seenAPIs := make(map[string]bool)
for _, api := range c.API {
if seenAPIs[api] {
return fmt.Errorf("repeated API namespace '%s'", api)
}

seenAPIs[api] = true
}

return nil
}

// DefaultJSONRPCConfig returns an EVM config with the JSON-RPC API enabled by default
Expand All @@ -123,6 +147,7 @@ func DefaultJSONRPCConfig() *JSONRPCConfig {
Address: DefaultJSONRPCAddress,
WsAddress: DefaultJSONRPCWsAddress,
EnableUnsafeCORS: false,
GasCap: DefaultGasCap,
}
}

Expand Down Expand Up @@ -150,17 +175,29 @@ func GetConfig(v *viper.Viper) Config {
Address: v.GetString("json-rpc.address"),
WsAddress: v.GetString("json-rpc.ws-address"),
EnableUnsafeCORS: v.GetBool("json-rpc.enable-unsafe-cors"),
GasCap: v.GetUint64("json-rpc.gas-cap"),
},
}
}

// ParseConfig retrieves the default environment configuration for the
// application.
func ParseConfig(v *viper.Viper) (*Config, error) {
conf := DefaultConfig()
err := v.Unmarshal(conf)

return conf, err
}

// ValidateBasic returns an error any of the application configuration fields are invalid
func (c Config) ValidateBasic() error {
if err := c.EVM.Validate(); err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrAppConfig, "invalid evm config value: %s", err.Error())
}

// TODO: validate JSON-RPC APIs
if err := c.JSONRPC.Validate(); err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrAppConfig, "invalid json-rpc config value: %s", err.Error())
}

return c.Config.ValidateBasic()
}
3 changes: 3 additions & 0 deletions server/config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ api = "{{range $index, $elmt := .JSONRPC.API}}{{if $index}},{{$elmt}}{{else}}{{$

# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk)
enable-unsafe-cors = "{{ .JSONRPC.EnableUnsafeCORS }}"

# GasCap sets a cap on gas that can be used in eth_call/estimateGas (0=infinite). Default: 25,000,000.
gas-cap = {{ .JSONRPC.GasCap }}
`
1 change: 1 addition & 0 deletions server/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const (
JSONRPCAddress = "json-rpc.address"
JSONWsAddress = "json-rpc.ws-address"
JSONEnableUnsafeCORS = "json-rpc.enable-unsafe-cors"
JSONRPCGasCap = "json-rpc.gas-cap"
)

// EVM flags
Expand Down
1 change: 1 addition & 0 deletions server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ which accepts a path for the resulting pprof file.
cmd.Flags().String(srvflags.JSONRPCAddress, config.DefaultJSONRPCAddress, "the JSON-RPC server address to listen on")
cmd.Flags().String(srvflags.JSONWsAddress, config.DefaultJSONRPCWsAddress, "the JSON-RPC WS server address to listen on")
cmd.Flags().Bool(srvflags.JSONEnableUnsafeCORS, false, "Define if the JSON-RPC server should enabled CORS (unsafe - use it at your own risk)")
cmd.Flags().Uint64(srvflags.JSONRPCGasCap, config.DefaultGasCap, "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)")

cmd.Flags().String(srvflags.EVMTracer, config.DefaultEVMTracer, "the EVM tracer type to collect execution traces from the EVM transaction execution (json|struct|access_list|markdown)")

Expand Down
8 changes: 0 additions & 8 deletions types/params.go

This file was deleted.

4 changes: 2 additions & 2 deletions x/evm/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ func (suite *KeeperTestSuite) deployTestContract(owner common.Address, supply *b

res, err := suite.queryClient.EstimateGas(ctx, &types.EthCallRequest{
Args: args,
GasCap: uint64(ethermint.DefaultRPCGasLimit),
GasCap: 25_000_000,
})
suite.Require().NoError(err)

Expand Down Expand Up @@ -805,7 +805,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest()
gasCap = ethermint.DefaultRPCGasLimit
gasCap = 25_000_000
tc.malleate()

args, err := json.Marshal(&args)
Expand Down