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

Commit

Permalink
feat: configurable JSON-RPC APIs (#349)
Browse files Browse the repository at this point in the history
* fix confusing name

* feat: Enable configurable grpc apis

* docs: Update docs and changelog

* Organized flags order

* fix linter

* fix linter

* fix maligned struct

* fix typo in docs

* fix unnecesary duplicate

* Update cmd/ethermintd/config/config.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update cmd/ethermintd/config/config.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update cmd/ethermintd/config/config.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update docs/basics/json_rpc.md

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* fix eth to be manage as default

* Update init.sh

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update tests/solidity/init-test-node.sh

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* add default case

* add default enable api namespaces

* update changelog

* fix namespaces array  handler

* remove duplicated changelog

* fix typo

* remove duplicates namespaces and fix eth namespace issue

* fix variable name

* break line in docs

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
  • Loading branch information
crypto-facs and fedekunze authored Jul 26, 2021
1 parent 5458126 commit d121272
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 60 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (rpc) [tharsis#176](https://github.com/tharsis/ethermint/issues/176) Support fetching pending nonce
* (rpc) [tharsis#272](https://github.com/tharsis/ethermint/pull/272) do binary search to estimate gas accurately
* (rpc) [#313](https://github.com/tharsis/ethermint/pull/313) Implement internal debug namespace (Not including logger functions nor traces).
* (rpc) [#349](https://github.com/tharsis/ethermint/pull/349) Implement configurable JSON-RPC APIs to manage enabled namespaces.

### Bug Fixes

Expand Down
27 changes: 18 additions & 9 deletions cmd/ethermintd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ const (
DefaultEVMWSAddress = "0.0.0.0:8546"
)

// GetDefaultAPINamespaces returns the default list of JSON-RPC namespaces that should be enabled
func GetDefaultAPINamespaces() []string {
return []string{"eth"}
}

// AppConfig helps to override default appConfig template and configs.
// return "", nil if no custom configuration is required for the application.
func AppConfig() (string, interface{}) {
Expand Down Expand Up @@ -57,27 +62,30 @@ func DefaultConfig() *Config {
}
}

// DefaultEVMConfig returns an EVM config with the JSON-RPC API enabled by default
func DefaultEVMConfig() *EVMRPCConfig {
return &EVMRPCConfig{
Enable: true,
RPCAddress: DefaultEVMAddress,
WsAddress: DefaultEVMWSAddress,
}
}

// EVMRPCConfig defines configuration for the EVM RPC server.
type EVMRPCConfig struct {
// RPCAddress defines the HTTP server to listen on
RPCAddress string `mapstructure:"address"`
// WsAddress defines the WebSocket server to listen on
WsAddress string `mapstructure:"ws-address"`
// API defines a list of JSON-RPC namespaces that should be enabled
API []string `mapstructure:"api"`
// Enable defines if the EVM RPC server should be enabled.
Enable bool `mapstructure:"enable"`
// EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk)
EnableUnsafeCORS bool `mapstructure:"enable-unsafe-cors"`
}

// DefaultEVMConfig returns an EVM config with the JSON-RPC API enabled by default
func DefaultEVMConfig() *EVMRPCConfig {
return &EVMRPCConfig{
Enable: true,
API: GetDefaultAPINamespaces(),
RPCAddress: DefaultEVMAddress,
WsAddress: DefaultEVMWSAddress,
}
}

// Config defines the server's top level configuration. It includes the default app config
// from the SDK as well as the EVM configuration to enable the JSON-RPC APIs.
type Config struct {
Expand All @@ -95,6 +103,7 @@ func GetConfig(v *viper.Viper) Config {
Config: cfg,
EVMRPC: EVMRPCConfig{
Enable: v.GetBool("evm-rpc.enable"),
API: v.GetStringSlice("evm-rpc.api"),
RPCAddress: v.GetString("evm-rpc.address"),
WsAddress: v.GetString("evm-rpc.ws-address"),
},
Expand Down
14 changes: 14 additions & 0 deletions docs/basics/json_rpc.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ Check the JSON-RPC methods and namespaces supported on Ethermint. {synopsis}
- [Ethereum JSON-RPC](https://eth.wiki/json-rpc/API) {prereq}
- [Geth JSON-RPC APIs](https://geth.ethereum.org/docs/rpc/server) {prereq}

## JSON-RPC Server

To enable RPC server use the following flag (set to true by default).

```
ethermintd start --evm-rpc.enable
```

By default, only `eth` namespace is enabled. In order to enable other namespaces use flag `--evm-rpc.api`.

```
ethermintd start --evm-rpc.api eth,txpool,personal,net,debug,web3
```

## JSON-RPC Methods

| Method | Namespace | Implemented | Notes |
Expand Down
134 changes: 87 additions & 47 deletions ethereum/rpc/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package rpc
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/server"

"github.com/ethereum/go-ethereum/rpc"
"github.com/tharsis/ethermint/ethereum/rpc/backend"
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/debug"
Expand Down Expand Up @@ -33,53 +32,94 @@ const (
)

// GetRPCAPIs returns the list of all APIs
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API {
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, selectedAPIs []string) []rpc.API {
nonceLock := new(types.AddrLocker)
backend := backend.NewEVMBackend(ctx.Logger, clientCtx)
ethAPI := eth.NewPublicAPI(ctx.Logger, clientCtx, backend, nonceLock)
evmBackend := backend.NewEVMBackend(ctx.Logger, clientCtx)
ethAPI := eth.NewPublicAPI(ctx.Logger, clientCtx, evmBackend, nonceLock)

var apis []rpc.API

// remove duplicates
selectedAPIs = unique(selectedAPIs)

for index := range selectedAPIs {
switch selectedAPIs[index] {
case EthNamespace:
apis = append(apis,
rpc.API{
Namespace: EthNamespace,
Version: apiVersion,
Service: ethAPI,
Public: true,
},
rpc.API{
Namespace: EthNamespace,
Version: apiVersion,
Service: filters.NewPublicAPI(ctx.Logger, tmWSClient, evmBackend),
Public: true,
},
)
case Web3Namespace:
apis = append(apis,
rpc.API{
Namespace: Web3Namespace,
Version: apiVersion,
Service: web3.NewPublicAPI(),
Public: true,
},
)
case NetNamespace:
apis = append(apis,
rpc.API{
Namespace: NetNamespace,
Version: apiVersion,
Service: net.NewPublicAPI(clientCtx),
Public: true,
},
)
case PersonalNamespace:
apis = append(apis,
rpc.API{
Namespace: PersonalNamespace,
Version: apiVersion,
Service: personal.NewAPI(ctx.Logger, ethAPI),
Public: true,
},
)
case TxPoolNamespace:
apis = append(apis,
rpc.API{
Namespace: TxPoolNamespace,
Version: apiVersion,
Service: txpool.NewPublicAPI(ctx.Logger),
Public: true,
},
)
case DebugNamespace:
apis = append(apis,
rpc.API{
Namespace: DebugNamespace,
Version: apiVersion,
Service: debug.NewInternalAPI(ctx),
Public: true,
},
)
default:
ctx.Logger.Error("invalid namespace value", "namespace", selectedAPIs[index])
}
}

return apis
}

return []rpc.API{
{
Namespace: Web3Namespace,
Version: apiVersion,
Service: web3.NewPublicAPI(),
Public: true,
},
{
Namespace: EthNamespace,
Version: apiVersion,
Service: ethAPI,
Public: true,
},
{
Namespace: EthNamespace,
Version: apiVersion,
Service: filters.NewPublicAPI(ctx.Logger, tmWSClient, backend),
Public: true,
},
{
Namespace: NetNamespace,
Version: apiVersion,
Service: net.NewPublicAPI(clientCtx),
Public: true,
},
{
Namespace: PersonalNamespace,
Version: apiVersion,
Service: personal.NewAPI(ctx.Logger, ethAPI),
Public: true,
},
{
Namespace: TxPoolNamespace,
Version: apiVersion,
Service: txpool.NewPublicAPI(ctx.Logger),
Public: true,
},
{
Namespace: DebugNamespace,
Version: apiVersion,
Service: debug.NewInternalAPI(ctx),
Public: true,
},
func unique(intSlice []string) []string {
keys := make(map[string]bool)
var list []string
for _, entry := range intSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}
2 changes: 1 addition & 1 deletion init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,4 @@ if [[ $1 == "pending" ]]; then
fi

# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
ethermintd start --pruning=nothing $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001aphoton
ethermintd start --pruning=nothing $TRACE --log_level $LOGLEVEL --minimum-gas-prices=0.0001aphoton --evm-rpc.api eth,txpool,personal,net,debug,web3
4 changes: 3 additions & 1 deletion server/evmrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ func StartEVMRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr string
tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint)

rpcServer := ethrpc.NewServer()
apis := rpc.GetRPCAPIs(ctx, clientCtx, tmWsClient)

rpcAPIArr := config.EVMRPC.API
apis := rpc.GetRPCAPIs(ctx, clientCtx, tmWsClient, rpcAPIArr)

for _, api := range apis {
if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil {
Expand Down
2 changes: 2 additions & 0 deletions server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const (
flagGRPCEnable = "grpc.enable"
flagGRPCAddress = "grpc.address"
flagEVMRPCEnable = "evm-rpc.enable"
flagEVMRPCAPI = "evm-rpc.api"
flagEVMRPCAddress = "evm-rpc.address"
flagEVMWSAddress = "evm-rpc.ws-address"
flagEVMEnableUnsafeCORS = "evm-rpc.enable-unsafe-cors"
Expand Down Expand Up @@ -179,6 +180,7 @@ which accepts a path for the resulting pprof file.
cmd.Flags().String(flagGRPCWebAddress, serverconfig.DefaultGRPCWebAddress, "The gRPC-Web server address to listen on")

cmd.Flags().Bool(flagEVMRPCEnable, true, "Define if the gRPC server should be enabled")
cmd.Flags().StringSlice(flagEVMRPCAPI, config.GetDefaultAPINamespaces(), "Defines a list of JSON-RPC namespaces that should be enabled")
cmd.Flags().String(flagEVMRPCAddress, config.DefaultEVMAddress, "the EVM RPC server address to listen on")
cmd.Flags().String(flagEVMWSAddress, config.DefaultEVMWSAddress, "the EVM WS server address to listen on")
cmd.Flags().Bool(flagEVMEnableUnsafeCORS, false, "Define if the EVM RPC server should enabled CORS (unsafe - use it at your own risk)")
Expand Down
2 changes: 1 addition & 1 deletion tests/solidity/init-test-node.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ ethermintd collect-gentxs
ethermintd validate-genesis

# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
ethermintd start --pruning=nothing --rpc.unsafe --keyring-backend test --trace --log_level info
ethermintd start --pruning=nothing --rpc.unsafe --keyring-backend test --trace --log_level info --evm-rpc.api eth,txpool,personal,net,debug,web3
4 changes: 3 additions & 1 deletion testutil/network/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ func startInProcess(cfg Config, val *Validator) error {

val.jsonRPC = jsonrpc.NewServer()

apis := rpc.GetRPCAPIs(val.Ctx, val.ClientCtx, tmWsClient)
rpcAPIArr := val.AppConfig.EVMRPC.API
apis := rpc.GetRPCAPIs(val.Ctx, val.ClientCtx, tmWsClient, rpcAPIArr)

for _, api := range apis {
if err := val.jsonRPC.RegisterName(api.Namespace, api.Service); err != nil {
return fmt.Errorf("failed to register JSON-RPC namespace %s: %w", api.Namespace, err)
Expand Down

0 comments on commit d121272

Please sign in to comment.