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#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
|
||||
|
||||
|
@ -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{}) {
|
||||
@ -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 {
|
||||
@ -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"),
|
||||
},
|
||||
|
@ -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 |
|
||||
|
@ -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"
|
||||
@ -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)
|
||||
|
||||
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,
|
||||
},
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
# 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)
|
||||
|
||||
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 {
|
||||
|
@ -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"
|
||||
@ -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)")
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user