feat: configurable JSON-RPC APIs (#349)
* 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>
This commit is contained in:
parent
54581269b8
commit
d1212725f8
@ -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#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) [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) [#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
|
### Bug Fixes
|
||||||
|
|
||||||
|
@ -18,6 +18,11 @@ const (
|
|||||||
DefaultEVMWSAddress = "0.0.0.0:8546"
|
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.
|
// AppConfig helps to override default appConfig template and configs.
|
||||||
// return "", nil if no custom configuration is required for the application.
|
// return "", nil if no custom configuration is required for the application.
|
||||||
func AppConfig() (string, interface{}) {
|
func AppConfig() (string, interface{}) {
|
||||||
@ -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.
|
// EVMRPCConfig defines configuration for the EVM RPC server.
|
||||||
type EVMRPCConfig struct {
|
type EVMRPCConfig struct {
|
||||||
// RPCAddress defines the HTTP server to listen on
|
// RPCAddress defines the HTTP server to listen on
|
||||||
RPCAddress string `mapstructure:"address"`
|
RPCAddress string `mapstructure:"address"`
|
||||||
// WsAddress defines the WebSocket server to listen on
|
// WsAddress defines the WebSocket server to listen on
|
||||||
WsAddress string `mapstructure:"ws-address"`
|
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 defines if the EVM RPC server should be enabled.
|
||||||
Enable bool `mapstructure:"enable"`
|
Enable bool `mapstructure:"enable"`
|
||||||
// EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk)
|
// EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk)
|
||||||
EnableUnsafeCORS bool `mapstructure:"enable-unsafe-cors"`
|
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
|
// 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.
|
// from the SDK as well as the EVM configuration to enable the JSON-RPC APIs.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -95,6 +103,7 @@ func GetConfig(v *viper.Viper) Config {
|
|||||||
Config: cfg,
|
Config: cfg,
|
||||||
EVMRPC: EVMRPCConfig{
|
EVMRPC: EVMRPCConfig{
|
||||||
Enable: v.GetBool("evm-rpc.enable"),
|
Enable: v.GetBool("evm-rpc.enable"),
|
||||||
|
API: v.GetStringSlice("evm-rpc.api"),
|
||||||
RPCAddress: v.GetString("evm-rpc.address"),
|
RPCAddress: v.GetString("evm-rpc.address"),
|
||||||
WsAddress: v.GetString("evm-rpc.ws-address"),
|
WsAddress: v.GetString("evm-rpc.ws-address"),
|
||||||
},
|
},
|
||||||
|
@ -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}
|
- [Ethereum JSON-RPC](https://eth.wiki/json-rpc/API) {prereq}
|
||||||
- [Geth JSON-RPC APIs](https://geth.ethereum.org/docs/rpc/server) {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
|
## JSON-RPC Methods
|
||||||
|
|
||||||
| Method | Namespace | Implemented | Notes |
|
| Method | Namespace | Implemented | Notes |
|
||||||
|
@ -5,7 +5,6 @@ package rpc
|
|||||||
import (
|
import (
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/tharsis/ethermint/ethereum/rpc/backend"
|
"github.com/tharsis/ethermint/ethereum/rpc/backend"
|
||||||
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/debug"
|
"github.com/tharsis/ethermint/ethereum/rpc/namespaces/debug"
|
||||||
@ -33,53 +32,94 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetRPCAPIs returns the list of all APIs
|
// 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)
|
nonceLock := new(types.AddrLocker)
|
||||||
backend := backend.NewEVMBackend(ctx.Logger, clientCtx)
|
evmBackend := backend.NewEVMBackend(ctx.Logger, clientCtx)
|
||||||
ethAPI := eth.NewPublicAPI(ctx.Logger, clientCtx, backend, nonceLock)
|
ethAPI := eth.NewPublicAPI(ctx.Logger, clientCtx, evmBackend, nonceLock)
|
||||||
|
|
||||||
return []rpc.API{
|
var apis []rpc.API
|
||||||
{
|
|
||||||
Namespace: Web3Namespace,
|
// remove duplicates
|
||||||
Version: apiVersion,
|
selectedAPIs = unique(selectedAPIs)
|
||||||
Service: web3.NewPublicAPI(),
|
|
||||||
Public: true,
|
for index := range selectedAPIs {
|
||||||
},
|
switch selectedAPIs[index] {
|
||||||
{
|
case EthNamespace:
|
||||||
|
apis = append(apis,
|
||||||
|
rpc.API{
|
||||||
Namespace: EthNamespace,
|
Namespace: EthNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: ethAPI,
|
Service: ethAPI,
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
rpc.API{
|
||||||
Namespace: EthNamespace,
|
Namespace: EthNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: filters.NewPublicAPI(ctx.Logger, tmWSClient, backend),
|
Service: filters.NewPublicAPI(ctx.Logger, tmWSClient, evmBackend),
|
||||||
Public: true,
|
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,
|
Namespace: NetNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: net.NewPublicAPI(clientCtx),
|
Service: net.NewPublicAPI(clientCtx),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
)
|
||||||
|
case PersonalNamespace:
|
||||||
|
apis = append(apis,
|
||||||
|
rpc.API{
|
||||||
Namespace: PersonalNamespace,
|
Namespace: PersonalNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: personal.NewAPI(ctx.Logger, ethAPI),
|
Service: personal.NewAPI(ctx.Logger, ethAPI),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
)
|
||||||
|
case TxPoolNamespace:
|
||||||
|
apis = append(apis,
|
||||||
|
rpc.API{
|
||||||
Namespace: TxPoolNamespace,
|
Namespace: TxPoolNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: txpool.NewPublicAPI(ctx.Logger),
|
Service: txpool.NewPublicAPI(ctx.Logger),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
)
|
||||||
|
case DebugNamespace:
|
||||||
|
apis = append(apis,
|
||||||
|
rpc.API{
|
||||||
Namespace: DebugNamespace,
|
Namespace: DebugNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: debug.NewInternalAPI(ctx),
|
Service: debug.NewInternalAPI(ctx),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
ctx.Logger.Error("invalid namespace value", "namespace", selectedAPIs[index])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return apis
|
||||||
|
}
|
||||||
|
|
||||||
|
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
init.sh
2
init.sh
@ -84,4 +84,4 @@ if [[ $1 == "pending" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
|
# 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
|
||||||
|
@ -21,7 +21,9 @@ func StartEVMRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr string
|
|||||||
tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint)
|
tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint)
|
||||||
|
|
||||||
rpcServer := ethrpc.NewServer()
|
rpcServer := ethrpc.NewServer()
|
||||||
apis := rpc.GetRPCAPIs(ctx, clientCtx, tmWsClient)
|
|
||||||
|
rpcAPIArr := config.EVMRPC.API
|
||||||
|
apis := rpc.GetRPCAPIs(ctx, clientCtx, tmWsClient, rpcAPIArr)
|
||||||
|
|
||||||
for _, api := range apis {
|
for _, api := range apis {
|
||||||
if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil {
|
if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil {
|
||||||
|
@ -72,6 +72,7 @@ const (
|
|||||||
flagGRPCEnable = "grpc.enable"
|
flagGRPCEnable = "grpc.enable"
|
||||||
flagGRPCAddress = "grpc.address"
|
flagGRPCAddress = "grpc.address"
|
||||||
flagEVMRPCEnable = "evm-rpc.enable"
|
flagEVMRPCEnable = "evm-rpc.enable"
|
||||||
|
flagEVMRPCAPI = "evm-rpc.api"
|
||||||
flagEVMRPCAddress = "evm-rpc.address"
|
flagEVMRPCAddress = "evm-rpc.address"
|
||||||
flagEVMWSAddress = "evm-rpc.ws-address"
|
flagEVMWSAddress = "evm-rpc.ws-address"
|
||||||
flagEVMEnableUnsafeCORS = "evm-rpc.enable-unsafe-cors"
|
flagEVMEnableUnsafeCORS = "evm-rpc.enable-unsafe-cors"
|
||||||
@ -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().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().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(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().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)")
|
cmd.Flags().Bool(flagEVMEnableUnsafeCORS, false, "Define if the EVM RPC server should enabled CORS (unsafe - use it at your own risk)")
|
||||||
|
@ -43,4 +43,4 @@ ethermintd collect-gentxs
|
|||||||
ethermintd validate-genesis
|
ethermintd validate-genesis
|
||||||
|
|
||||||
# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
|
# 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
|
||||||
|
@ -121,7 +121,9 @@ func startInProcess(cfg Config, val *Validator) error {
|
|||||||
|
|
||||||
val.jsonRPC = jsonrpc.NewServer()
|
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 {
|
for _, api := range apis {
|
||||||
if err := val.jsonRPC.RegisterName(api.Namespace, api.Service); err != nil {
|
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)
|
return fmt.Errorf("failed to register JSON-RPC namespace %s: %w", api.Namespace, err)
|
||||||
|
Loading…
Reference in New Issue
Block a user