Skip to content

Commit

Permalink
feat(evm): app config and json-rpc (#1871)
Browse files Browse the repository at this point in the history
  • Loading branch information
onikonychev authored May 15, 2024
1 parent fac6492 commit aeff126
Show file tree
Hide file tree
Showing 10 changed files with 998 additions and 41 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1856](https://github.com/NibiruChain/nibiru/pull/1856) - feat(eth-rpc): Conversion types and functions between Ethereum txs and blocks and Tendermint ones.
- [#1861](https://github.com/NibiruChain/nibiru/pull/1861) - feat(eth-rpc): RPC backend, Ethereum tracer, KV indexer, and RPC APIs
- [#1869](https://github.com/NibiruChain/nibiru/pull/1869) - feat(eth): Module and start of keeper tests
- [#1871](https://github.com/NibiruChain/nibiru/pull/1871) - feat(evm): app config and json-rpc
- [#1873](https://github.com/NibiruChain/nibiru/pull/1873) - feat(evm): keeper collections and grpc query impls for EthAccount, NibiruAccount

#### Dapp modules: perp, spot, oracle, etc
Expand Down
2 changes: 1 addition & 1 deletion app/server/config/server_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func GetAPINamespaces() []string {
// DefaultJSONRPCConfig returns an EVM config with the JSON-RPC API enabled by default
func DefaultJSONRPCConfig() *JSONRPCConfig {
return &JSONRPCConfig{
Enable: false,
Enable: true,
API: GetDefaultAPINamespaces(),
Address: DefaultJSONRPCAddress,
WsAddress: DefaultJSONRPCWsAddress,
Expand Down
93 changes: 93 additions & 0 deletions app/server/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package server

import (
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// Tendermint/cosmos-sdk full-node start flags
const (
WithTendermint = "with-tendermint"
Address = "address"
Transport = "transport"
TraceStore = "trace-store"
CPUProfile = "cpu-profile"
// The type of database for application and snapshots databases
AppDBBackend = "app-db-backend"
)

// GRPC-related flags.
const (
GRPCOnly = "grpc-only"
GRPCEnable = "grpc.enable"
GRPCAddress = "grpc.address"
GRPCWebEnable = "grpc-web.enable"
GRPCWebAddress = "grpc-web.address"
)

// Cosmos API flags
const (
RPCEnable = "api.enable"
EnabledUnsafeCors = "api.enabled-unsafe-cors"
)

// JSON-RPC flags
const (
JSONRPCEnable = "json-rpc.enable"
JSONRPCAPI = "json-rpc.api"
JSONRPCAddress = "json-rpc.address"
JSONWsAddress = "json-rpc.ws-address"
JSONRPCGasCap = "json-rpc.gas-cap"
JSONRPCEVMTimeout = "json-rpc.evm-timeout"
JSONRPCTxFeeCap = "json-rpc.txfee-cap"
JSONRPCFilterCap = "json-rpc.filter-cap"
JSONRPCLogsCap = "json-rpc.logs-cap"
JSONRPCBlockRangeCap = "json-rpc.block-range-cap"
JSONRPCHTTPTimeout = "json-rpc.http-timeout"
JSONRPCHTTPIdleTimeout = "json-rpc.http-idle-timeout"
JSONRPCAllowUnprotectedTxs = "json-rpc.allow-unprotected-txs"
JSONRPCMaxOpenConnections = "json-rpc.max-open-connections"
JSONRPCEnableIndexer = "json-rpc.enable-indexer"
JSONRPCEnableMetrics = "metrics"
)

// EVM flags
const (
EVMTracer = "evm.tracer"
EVMMaxTxGasWanted = "evm.max-tx-gas-wanted"
)

// TLS flags
const (
TLSCertPath = "tls.certificate-path"
TLSKeyPath = "tls.key-path"
)

// AddTxFlags adds common flags for commands to post tx
func AddTxFlags(cmd *cobra.Command) (*cobra.Command, error) {
cmd.PersistentFlags().String(flags.FlagChainID, "", "Specify Chain ID for sending Tx")
cmd.PersistentFlags().String(flags.FlagFrom, "", "Name or address of private key with which to sign")
cmd.PersistentFlags().String(flags.FlagFees, "", "Fees to pay along with transaction; eg: 5000unibi")
cmd.PersistentFlags().String(flags.FlagGasPrices, "", "Gas prices to determine the transaction fee (e.g. 5000unibi)")
cmd.PersistentFlags().String(flags.FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain") //nolint:lll
cmd.PersistentFlags().Float64(flags.FlagGasAdjustment, flags.DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ") //nolint:lll
cmd.PersistentFlags().StringP(flags.FlagBroadcastMode, "b", flags.BroadcastSync, "Transaction broadcasting mode (sync|async)")
cmd.PersistentFlags().String(flags.FlagKeyringBackend, keyring.BackendOS, "Select keyring's backend")

// --gas can accept integers and "simulate"
// cmd.PersistentFlags().Var(&flags.GasFlagVar, "gas", fmt.Sprintf(
// "gas limit to set per-transaction; set to %q to calculate required gas automatically (default %d)",
// flags.GasFlagAuto, flags.DefaultGasLimit,
// ))

// viper.BindPFlag(flags.FlagTrustNode, cmd.Flags().Lookup(flags.FlagTrustNode))
if err := viper.BindPFlag(flags.FlagNode, cmd.PersistentFlags().Lookup(flags.FlagNode)); err != nil {
return nil, err
}
if err := viper.BindPFlag(flags.FlagKeyringBackend, cmd.PersistentFlags().Lookup(flags.FlagKeyringBackend)); err != nil {
return nil, err
}
return cmd, nil
}
114 changes: 114 additions & 0 deletions app/server/json_rpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package server

import (
"net/http"
"time"

"github.com/NibiruChain/nibiru/eth"
"github.com/NibiruChain/nibiru/eth/rpc/rpcapi"

"github.com/gorilla/mux"
"github.com/rs/cors"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/types"
ethlog "github.com/ethereum/go-ethereum/log"
ethrpc "github.com/ethereum/go-ethereum/rpc"

srvconfig "github.com/NibiruChain/nibiru/app/server/config"
)

// StartJSONRPC starts the JSON-RPC server
func StartJSONRPC(ctx *server.Context,
clientCtx client.Context,
tmRPCAddr,
tmEndpoint string,
config *srvconfig.Config,
indexer eth.EVMTxIndexer,
) (*http.Server, chan struct{}, error) {
tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint, ctx.Logger)

logger := ctx.Logger.With("module", "geth")
ethlog.Root().SetHandler(ethlog.FuncHandler(func(r *ethlog.Record) error {
switch r.Lvl {
case ethlog.LvlTrace, ethlog.LvlDebug:
logger.Debug(r.Msg, r.Ctx...)
case ethlog.LvlInfo, ethlog.LvlWarn:
logger.Info(r.Msg, r.Ctx...)
case ethlog.LvlError, ethlog.LvlCrit:
logger.Error(r.Msg, r.Ctx...)
}
return nil
}))

rpcServer := ethrpc.NewServer()

allowUnprotectedTxs := config.JSONRPC.AllowUnprotectedTxs
rpcAPIArr := config.JSONRPC.API

apis := rpcapi.GetRPCAPIs(ctx, clientCtx, tmWsClient, allowUnprotectedTxs, indexer, rpcAPIArr)

for _, api := range apis {
if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil {
ctx.Logger.Error(
"failed to register service in JSON RPC namespace",
"namespace", api.Namespace,
"service", api.Service,
)
return nil, nil, err
}
}

r := mux.NewRouter()
r.HandleFunc("/", rpcServer.ServeHTTP).Methods("POST")

handlerWithCors := cors.Default()
if config.API.EnableUnsafeCORS {
handlerWithCors = cors.AllowAll()
}

httpSrv := &http.Server{
Addr: config.JSONRPC.Address,
Handler: handlerWithCors.Handler(r),
ReadHeaderTimeout: config.JSONRPC.HTTPTimeout,
ReadTimeout: config.JSONRPC.HTTPTimeout,
WriteTimeout: config.JSONRPC.HTTPTimeout,
IdleTimeout: config.JSONRPC.HTTPIdleTimeout,
}
httpSrvDone := make(chan struct{}, 1)

ln, err := Listen(httpSrv.Addr, config)
if err != nil {
return nil, nil, err
}

errCh := make(chan error)
go func() {
ctx.Logger.Info("Starting JSON-RPC server", "address", config.JSONRPC.Address)
if err := httpSrv.Serve(ln); err != nil {
if err == http.ErrServerClosed {
close(httpSrvDone)
return
}

ctx.Logger.Error("failed to start JSON-RPC server", "error", err.Error())
errCh <- err
}
}()

select {
case err := <-errCh:
ctx.Logger.Error("failed to boot JSON-RPC server", "error", err.Error())
return nil, nil, err
case <-time.After(types.ServerStartTime): // assume JSON RPC server started successfully
}

ctx.Logger.Info("Starting JSON WebSocket server", "address", config.JSONRPC.WsAddress)

// allocate separate WS connection to Tendermint
tmWsClient = ConnectTmWS(tmRPCAddr, tmEndpoint, ctx.Logger)
wsSrv := rpcapi.NewWebsocketsServer(clientCtx, ctx.Logger, tmWsClient, config)
wsSrv.Start()
return httpSrv, httpSrvDone, nil
}
Loading

0 comments on commit aeff126

Please sign in to comment.