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

Add query-only mode flag #1360

Merged
merged 17 commits into from
Oct 19, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (ledger) [#1277](https://github.com/evmos/ethermint/pull/1277) Add Ledger preprocessing transaction hook for EIP-712-signed Cosmos payloads.
* (rpc) [#1296](https://github.com/evmos/ethermint/pull/1296) Add RPC Backend unit tests.
* (rpc) [#1352](https://github.com/evmos/ethermint/pull/1352) Make the grpc queries run concurrently, don't block the consensus state machine.
* (cli) [#1360](https://github.com/evmos/ethermint/pull/1360) Introduce `json-rpc-only` and `grpc-only` flag, such that when enabled, will start the node in a query-only mode.

### Bug Fixes

Expand Down
4 changes: 2 additions & 2 deletions gomod2nix.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ schema = 3
version = "v0.19.2-0.20220916140702-9b6be3095313"
hash = "sha256-49xr/7/4L1wZ45eW5lE7C4SlcbGf4gBY+662SfJiWPQ="
[mod."github.com/cosmos/ibc-go/v5"]
version = "v5.0.0-rc2"
hash = "sha256-p4tpb6I6bdXix1sTYivJEygUtM4q+nTIKdSlf6c/LCw="
version = "v5.0.0"
hash = "sha256-sDZdmuGohaaBF7bxrjo9PWJnmoF+VOkjySYhsFixPz4="
[mod."github.com/cosmos/ledger-cosmos-go"]
version = "v0.11.1"
hash = "sha256-yli+VvVtZmHo2LPvCY6lYVUfcCDn3sBLDL+a8KIlqDA="
Expand Down
3 changes: 3 additions & 0 deletions server/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ const (
AppDBBackend = "app-db-backend"
)

const JSONRPCOnly = "json-rpc-only"
fedekunze marked this conversation as resolved.
Show resolved Hide resolved

// GRPC-related flags.
const (
GRPCOnly = "grpc-only"
GRPCEnable = "grpc.enable"
GRPCAddress = "grpc.address"
GRPCWebEnable = "grpc-web.enable"
Expand Down
178 changes: 91 additions & 87 deletions server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ which accepts a path for the resulting pprof file.
cmd.Flags().Uint64(server.FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune Tendermint blocks")
cmd.Flags().String(srvflags.AppDBBackend, "", "The type of database for application and snapshots databases")

cmd.Flags().Bool(srvflags.JSONRPCOnly, false, "Start the node in query only mode without Tendermint process")
cmd.Flags().Bool(srvflags.GRPCOnly, false, "Start the node in gRPC query only mode without Tendermint process")
cmd.Flags().Bool(srvflags.GRPCEnable, true, "Define if the gRPC server should be enabled")
cmd.Flags().String(srvflags.GRPCAddress, serverconfig.DefaultGRPCAddress, "the gRPC server address to listen on")
cmd.Flags().Bool(srvflags.GRPCWebEnable, true, "Define if the gRPC-Web server should be enabled. (Note: gRPC must also be enabled.)")
Expand All @@ -156,7 +158,7 @@ which accepts a path for the resulting pprof file.
cmd.Flags().Bool(srvflags.RPCEnable, false, "Defines if Cosmos-sdk REST server should be enabled")
cmd.Flags().Bool(srvflags.EnabledUnsafeCors, false, "Defines if CORS should be enabled (unsafe - use it at your own risk)")

cmd.Flags().Bool(srvflags.JSONRPCEnable, true, "Define if the gRPC server should be enabled")
cmd.Flags().Bool(srvflags.JSONRPCEnable, true, "Define if the JSON-RPC server should be enabled")
cmd.Flags().StringSlice(srvflags.JSONRPCAPI, config.GetDefaultAPINamespaces(), "Defines a list of JSON-RPC namespaces that should be enabled")
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")
Expand Down Expand Up @@ -236,8 +238,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
cfg := ctx.Config
home := cfg.RootDir
logger := ctx.Logger
var cpuProfileCleanup func() error

if cpuProfile := ctx.Viper.GetString(srvflags.CPUProfile); cpuProfile != "" {
fp, err := ethdebug.ExpandHome(cpuProfile)
if err != nil {
Expand All @@ -254,15 +254,13 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
return err
}

cpuProfileCleanup = func() error {
defer func() {
ctx.Logger.Info("stopping CPU profiler", "profile", cpuProfile)
pprof.StopCPUProfile()
if err := f.Close(); err != nil {
logger.Error("failed to close CPU profiler file", "error", err.Error())
return err
}
return nil
}
}()
}

traceWriterFile := ctx.Viper.GetString(srvflags.TraceStore)
Expand Down Expand Up @@ -310,30 +308,51 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
}

genDocProvider := node.DefaultGenesisDocProviderFunc(cfg)
tmNode, err := node.NewNode(
cfg,
pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()),
nodeKey,
proxy.NewLocalClientCreator(app),
genDocProvider,
node.DefaultDBProvider,
node.DefaultMetricsProvider(cfg.Instrumentation),
ctx.Logger.With("server", "node"),
var (
tmNode *node.Node
jsonRPCOnly = ctx.Viper.GetBool(srvflags.JSONRPCOnly)
gRPCOnly = ctx.Viper.GetBool(srvflags.GRPCOnly)
)
if err != nil {
logger.Error("failed init node", "error", err.Error())
return err
}
if jsonRPCOnly || gRPCOnly {
ctx.Logger.Info("starting node in query only mode; Tendermint is disabled")
config.GRPC.Enable = true
if jsonRPCOnly {
config.JSONRPC.Enable = true
}
config.JSONRPC.EnableIndexer = false
} else {
tmNode, err = node.NewNode(
cfg,
pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()),
nodeKey,
proxy.NewLocalClientCreator(app),
genDocProvider,
node.DefaultDBProvider,
node.DefaultMetricsProvider(cfg.Instrumentation),
ctx.Logger.With("server", "node"),
)
if err != nil {
logger.Error("failed init node", "error", err.Error())
return err
}

if err := tmNode.Start(); err != nil {
logger.Error("failed start tendermint server", "error", err.Error())
return err
if err := tmNode.Start(); err != nil {
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
logger.Error("failed start tendermint server", "error", err.Error())
return err
}

defer func() {
if tmNode.IsRunning() {
_ = tmNode.Stop()
Fixed Show fixed Hide fixed
}
logger.Info("Bye!")
}()
}

// Add the tx service to the gRPC router. We only need to register this
// service if API or gRPC or JSONRPC is enabled, and avoid doing so in the general
// case, because it spawns a new local tendermint RPC client.
if config.API.Enable || config.GRPC.Enable || config.JSONRPC.Enable || config.JSONRPC.EnableIndexer {
if (config.API.Enable || config.GRPC.Enable || config.JSONRPC.Enable || config.JSONRPC.EnableIndexer) && tmNode != nil {
clientCtx = clientCtx.WithClient(local.New(tmNode))

app.RegisterTxService(clientCtx)
Expand Down Expand Up @@ -420,7 +439,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
apiSrv = api.New(clientCtx, ctx.Logger.With("server", "api"))
app.RegisterAPIRoutes(apiSrv, config.API)
errCh := make(chan error)

go func() {
if err := apiSrv.Start(config.Config); err != nil {
errCh <- err
Expand All @@ -432,6 +450,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
return err
case <-time.After(types.ServerStartTime): // assume server started successfully
}
defer apiSrv.Close()
}

var (
Expand All @@ -443,15 +462,62 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
if err != nil {
return err
}
defer grpcSrv.Stop()
if config.GRPCWeb.Enable {
grpcWebSrv, err = servergrpc.StartGRPCWeb(grpcSrv, config.Config)
if err != nil {
ctx.Logger.Error("failed to start grpc-web http server", "error", err)
return err
}
defer func() {
if err := grpcWebSrv.Close(); err != nil {
logger.Error("failed to close the grpcWebSrc", "error", err.Error())
}
}()
}
}

var (
httpSrv *http.Server
httpSrvDone chan struct{}
)

if config.JSONRPC.Enable {
genDoc, err := genDocProvider()
if err != nil {
return err
}

clientCtx := clientCtx.WithChainID(genDoc.ChainID)

tmEndpoint := "/websocket"
tmRPCAddr := cfg.RPC.ListenAddress
httpSrv, httpSrvDone, err = StartJSONRPC(ctx, clientCtx, tmRPCAddr, tmEndpoint, &config, idxer)
if err != nil {
return err
}
defer func() {
shutdownCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
defer cancelFn()
if err := httpSrv.Shutdown(shutdownCtx); err != nil {
logger.Error("HTTP server shutdown produced a warning", "error", err.Error())
} else {
logger.Info("HTTP server shut down, waiting 5 sec")
select {
case <-time.Tick(5 * time.Second):
case <-httpSrvDone:
}
}
}()
}

// At this point it is safe to block the process if we're in query only mode as
// we do not need to start Rosetta or handle any Tendermint related processes.
if jsonRPCOnly || gRPCOnly {
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
// wait for signal capture and gracefully return
return server.WaitForQuitSignals()
}

var rosettaSrv crgserver.Server
if config.Rosetta.Enable {
offlineMode := config.Rosetta.Offline
Expand Down Expand Up @@ -487,68 +553,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
case <-time.After(types.ServerStartTime): // assume server started successfully
}
}

var (
httpSrv *http.Server
httpSrvDone chan struct{}
)

if config.JSONRPC.Enable {
genDoc, err := genDocProvider()
if err != nil {
return err
}

clientCtx := clientCtx.WithChainID(genDoc.ChainID)

tmEndpoint := "/websocket"
tmRPCAddr := cfg.RPC.ListenAddress
httpSrv, httpSrvDone, err = StartJSONRPC(ctx, clientCtx, tmRPCAddr, tmEndpoint, &config, idxer)
if err != nil {
return err
}
}

defer func() {
if tmNode.IsRunning() {
_ = tmNode.Stop()
}

if cpuProfileCleanup != nil {
_ = cpuProfileCleanup()
}

if apiSrv != nil {
_ = apiSrv.Close()
}

if grpcSrv != nil {
grpcSrv.Stop()
if grpcWebSrv != nil {
if err := grpcWebSrv.Close(); err != nil {
logger.Error("failed to close the grpcWebSrc", "error", err.Error())
}
}
}

if httpSrv != nil {
shutdownCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
defer cancelFn()

if err := httpSrv.Shutdown(shutdownCtx); err != nil {
logger.Error("HTTP server shutdown produced a warning", "error", err.Error())
} else {
logger.Info("HTTP server shut down, waiting 5 sec")
select {
case <-time.Tick(5 * time.Second):
case <-httpSrvDone:
}
}
}

logger.Info("Bye!")
}()

// Wait for SIGINT or SIGTERM signal
return server.WaitForQuitSignals()
}
Expand Down