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. | ||||
| * (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 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 | ||||
| 
 | ||||
| ### Bug Fixes | ||||
|  | ||||
| @ -20,6 +20,7 @@ const ( | ||||
| 
 | ||||
| // GRPC-related flags.
 | ||||
| const ( | ||||
| 	GRPCOnly       = "grpc-only" | ||||
| 	GRPCEnable     = "grpc.enable" | ||||
| 	GRPCAddress    = "grpc.address" | ||||
| 	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().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().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.)") | ||||
| @ -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.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") | ||||
| @ -239,8 +240,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 { | ||||
| @ -257,15 +256,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) | ||||
| @ -313,30 +310,47 @@ 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 | ||||
| 		gRPCOnly = ctx.Viper.GetBool(srvflags.GRPCOnly) | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		logger.Error("failed init node", "error", err.Error()) | ||||
| 		return err | ||||
| 	} | ||||
| 	if gRPCOnly { | ||||
| 		ctx.Logger.Info("starting node in query only mode; Tendermint is disabled") | ||||
| 		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 { | ||||
| 		logger.Error("failed start tendermint server", "error", err.Error()) | ||||
| 		return err | ||||
| 		if err := tmNode.Start(); err != nil { | ||||
| 			logger.Error("failed start tendermint server", "error", err.Error()) | ||||
| 			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
 | ||||
| 	// 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) | ||||
| @ -429,7 +443,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 | ||||
| @ -441,6 +454,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 ( | ||||
| @ -452,15 +466,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 gRPCOnly { | ||||
| 		// wait for signal capture and gracefully return
 | ||||
| 		return server.WaitForQuitSignals() | ||||
| 	} | ||||
| 
 | ||||
| 	var rosettaSrv crgserver.Server | ||||
| 	if config.Rosetta.Enable { | ||||
| 		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
 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	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() | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user