imp(server): Add query-only mode flag for gRPC (#1360)
* add grpc only mode flag * add change log * add tmNode nil check * only flag to modes * fix close for query mode * fix hint * keep grpc-only & json-rpc-only * rm space * mv apiSrv close * mv cpuProfileCleanup * mv tmNode stop * disable indexer on query only which need tm client on start * update nix * revert json-rpc-only change
This commit is contained in:
		
							parent
							
								
									db94d8ec23
								
							
						
					
					
						commit
						236ca33c53
					
				| @ -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. | * (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) [#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. | * (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 a new `grpc-only` flag, such that when enabled, will start the node in a query-only mode. Note, gRPC MUST be enabled with this flag. | ||||||
| * (rpc) [#1378](https://github.com/evmos/ethermint/pull/1378) Add support for EVM RPC metrics | * (rpc) [#1378](https://github.com/evmos/ethermint/pull/1378) Add support for EVM RPC metrics | ||||||
| 
 | 
 | ||||||
| ### Bug Fixes | ### Bug Fixes | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ const ( | |||||||
| 
 | 
 | ||||||
| // GRPC-related flags.
 | // GRPC-related flags.
 | ||||||
| const ( | const ( | ||||||
|  | 	GRPCOnly       = "grpc-only" | ||||||
| 	GRPCEnable     = "grpc.enable" | 	GRPCEnable     = "grpc.enable" | ||||||
| 	GRPCAddress    = "grpc.address" | 	GRPCAddress    = "grpc.address" | ||||||
| 	GRPCWebEnable  = "grpc-web.enable" | 	GRPCWebEnable  = "grpc-web.enable" | ||||||
|  | |||||||
							
								
								
									
										173
									
								
								server/start.go
									
									
									
									
									
								
							
							
						
						
									
										173
									
								
								server/start.go
									
									
									
									
									
								
							| @ -150,6 +150,7 @@ 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().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().String(srvflags.AppDBBackend, "", "The type of database for application and snapshots databases") | ||||||
| 
 | 
 | ||||||
|  | 	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().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().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.)") | 	cmd.Flags().Bool(srvflags.GRPCWebEnable, true, "Define if the gRPC-Web server should be enabled. (Note: gRPC must also be enabled.)") | ||||||
| @ -158,7 +159,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.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.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().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.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") | 	cmd.Flags().String(srvflags.JSONWsAddress, config.DefaultJSONRPCWsAddress, "the JSON-RPC WS server address to listen on") | ||||||
| @ -239,8 +240,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty | |||||||
| 	cfg := ctx.Config | 	cfg := ctx.Config | ||||||
| 	home := cfg.RootDir | 	home := cfg.RootDir | ||||||
| 	logger := ctx.Logger | 	logger := ctx.Logger | ||||||
| 	var cpuProfileCleanup func() error |  | ||||||
| 
 |  | ||||||
| 	if cpuProfile := ctx.Viper.GetString(srvflags.CPUProfile); cpuProfile != "" { | 	if cpuProfile := ctx.Viper.GetString(srvflags.CPUProfile); cpuProfile != "" { | ||||||
| 		fp, err := ethdebug.ExpandHome(cpuProfile) | 		fp, err := ethdebug.ExpandHome(cpuProfile) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @ -257,15 +256,13 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty | |||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		cpuProfileCleanup = func() error { | 		defer func() { | ||||||
| 			ctx.Logger.Info("stopping CPU profiler", "profile", cpuProfile) | 			ctx.Logger.Info("stopping CPU profiler", "profile", cpuProfile) | ||||||
| 			pprof.StopCPUProfile() | 			pprof.StopCPUProfile() | ||||||
| 			if err := f.Close(); err != nil { | 			if err := f.Close(); err != nil { | ||||||
| 				logger.Error("failed to close CPU profiler file", "error", err.Error()) | 				logger.Error("failed to close CPU profiler file", "error", err.Error()) | ||||||
| 				return err |  | ||||||
| 			} | 			} | ||||||
| 			return nil | 		}() | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	traceWriterFile := ctx.Viper.GetString(srvflags.TraceStore) | 	traceWriterFile := ctx.Viper.GetString(srvflags.TraceStore) | ||||||
| @ -313,30 +310,47 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	genDocProvider := node.DefaultGenesisDocProviderFunc(cfg) | 	genDocProvider := node.DefaultGenesisDocProviderFunc(cfg) | ||||||
| 	tmNode, err := node.NewNode( | 	var ( | ||||||
| 		cfg, | 		tmNode   *node.Node | ||||||
| 		pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()), | 		gRPCOnly = ctx.Viper.GetBool(srvflags.GRPCOnly) | ||||||
| 		nodeKey, |  | ||||||
| 		proxy.NewLocalClientCreator(app), |  | ||||||
| 		genDocProvider, |  | ||||||
| 		node.DefaultDBProvider, |  | ||||||
| 		node.DefaultMetricsProvider(cfg.Instrumentation), |  | ||||||
| 		ctx.Logger.With("server", "node"), |  | ||||||
| 	) | 	) | ||||||
| 	if err != nil { | 	if gRPCOnly { | ||||||
| 		logger.Error("failed init node", "error", err.Error()) | 		ctx.Logger.Info("starting node in query only mode; Tendermint is disabled") | ||||||
| 		return err | 		config.GRPC.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 { | 		if err := tmNode.Start(); err != nil { | ||||||
| 		logger.Error("failed start tendermint server", "error", err.Error()) | 			logger.Error("failed start tendermint server", "error", err.Error()) | ||||||
| 		return err | 			return err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		defer func() { | ||||||
|  | 			if tmNode.IsRunning() { | ||||||
|  | 				_ = tmNode.Stop() | ||||||
|  | 			} | ||||||
|  | 			logger.Info("Bye!") | ||||||
|  | 		}() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Add the tx service to the gRPC router. We only need to register this
 | 	// 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
 | 	// 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.
 | 	// 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)) | 		clientCtx = clientCtx.WithClient(local.New(tmNode)) | ||||||
| 
 | 
 | ||||||
| 		app.RegisterTxService(clientCtx) | 		app.RegisterTxService(clientCtx) | ||||||
| @ -429,7 +443,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty | |||||||
| 		apiSrv = api.New(clientCtx, ctx.Logger.With("server", "api")) | 		apiSrv = api.New(clientCtx, ctx.Logger.With("server", "api")) | ||||||
| 		app.RegisterAPIRoutes(apiSrv, config.API) | 		app.RegisterAPIRoutes(apiSrv, config.API) | ||||||
| 		errCh := make(chan error) | 		errCh := make(chan error) | ||||||
| 
 |  | ||||||
| 		go func() { | 		go func() { | ||||||
| 			if err := apiSrv.Start(config.Config); err != nil { | 			if err := apiSrv.Start(config.Config); err != nil { | ||||||
| 				errCh <- err | 				errCh <- err | ||||||
| @ -441,6 +454,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty | |||||||
| 			return err | 			return err | ||||||
| 		case <-time.After(types.ServerStartTime): // assume server started successfully
 | 		case <-time.After(types.ServerStartTime): // assume server started successfully
 | ||||||
| 		} | 		} | ||||||
|  | 		defer apiSrv.Close() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var ( | 	var ( | ||||||
| @ -452,15 +466,62 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty | |||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|  | 		defer grpcSrv.Stop() | ||||||
| 		if config.GRPCWeb.Enable { | 		if config.GRPCWeb.Enable { | ||||||
| 			grpcWebSrv, err = servergrpc.StartGRPCWeb(grpcSrv, config.Config) | 			grpcWebSrv, err = servergrpc.StartGRPCWeb(grpcSrv, config.Config) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				ctx.Logger.Error("failed to start grpc-web http server", "error", err) | 				ctx.Logger.Error("failed to start grpc-web http server", "error", err) | ||||||
| 				return 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 gRPCOnly { | ||||||
|  | 		// wait for signal capture and gracefully return
 | ||||||
|  | 		return server.WaitForQuitSignals() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	var rosettaSrv crgserver.Server | 	var rosettaSrv crgserver.Server | ||||||
| 	if config.Rosetta.Enable { | 	if config.Rosetta.Enable { | ||||||
| 		offlineMode := config.Rosetta.Offline | 		offlineMode := config.Rosetta.Offline | ||||||
| @ -496,68 +557,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty | |||||||
| 		case <-time.After(types.ServerStartTime): // assume server started successfully
 | 		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
 | 	// Wait for SIGINT or SIGTERM signal
 | ||||||
| 	return server.WaitForQuitSignals() | 	return server.WaitForQuitSignals() | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user