From 97cfd71b2302b8e2fa87c797046db3973a4664b4 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:27:36 +0200 Subject: [PATCH] feat(server): Start grpc and api server in standalone mode (v0.50.x) (#18163) --- CHANGELOG.md | 3 ++ docs/docs/user/run-node/01-run-node.md | 7 +++++ server/start.go | 38 ++++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 856844fd0c..67938089cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Features + +* (server) [#18162](https://github.com/cosmos/cosmos-sdk/pull/18162) Start gRPC & API server in standalone mode ### Improvements * (x/staking/keeper) [#]18049(https://github.com/cosmos/cosmos-sdk/pull/18049) return early if Slash encounters zero tokens to burn. diff --git a/docs/docs/user/run-node/01-run-node.md b/docs/docs/user/run-node/01-run-node.md index a9ef422b68..f16eb42f52 100644 --- a/docs/docs/user/run-node/01-run-node.md +++ b/docs/docs/user/run-node/01-run-node.md @@ -157,6 +157,13 @@ The previous command allow you to run a single node. This is enough for the next The naive way would be to run the same commands again in separate terminal windows. This is possible, however in the Cosmos SDK, we leverage the power of [Docker Compose](https://docs.docker.com/compose/) to run a localnet. If you need inspiration on how to set up your own localnet with Docker Compose, you can have a look at the Cosmos SDK's [`docker-compose.yml`](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/docker-compose.yml). +### Standalone App/CometBFT + +By default, the Cosmos SDK runs CometBFT in-process with the application +If you want to run the application and CometBFT in separate processes, +start the application with the `--with-comet=false` flag +and set `rpc.laddr` in `config.toml` to the CometBFT node's RPC address. + ## Logging Logging provides a way to see what is going on with a node. By default the info level is set. This is a global level and all info logs will be outputted to the terminal. If you would like to filter specific logs to the terminal instead of all, then setting `module:log_level` is how this can work. diff --git a/server/start.go b/server/start.go index ed33941ab4..a8e250f0e0 100644 --- a/server/start.go +++ b/server/start.go @@ -15,6 +15,7 @@ import ( "github.com/cometbft/cometbft/p2p" pvm "github.com/cometbft/cometbft/privval" "github.com/cometbft/cometbft/proxy" + rpchttp "github.com/cometbft/cometbft/rpc/client/http" "github.com/cometbft/cometbft/rpc/client/local" cmttypes "github.com/cometbft/cometbft/types" dbm "github.com/cosmos/cosmos-db" @@ -247,12 +248,12 @@ func start(svrCtx *Context, clientCtx client.Context, appCreator types.AppCreato emitServerInfoMetrics() if !withCmt { - return startStandAlone(svrCtx, app, opts) + return startStandAlone(svrCtx, svrCfg, clientCtx, app, metrics, opts) } return startInProcess(svrCtx, svrCfg, clientCtx, app, metrics, opts) } -func startStandAlone(svrCtx *Context, app types.Application, opts StartCmdOptions) error { +func startStandAlone(svrCtx *Context, svrCfg serverconfig.Config, clientCtx client.Context, app types.Application, metrics *telemetry.Metrics, opts StartCmdOptions) error { addr := svrCtx.Viper.GetString(flagAddress) transport := svrCtx.Viper.GetString(flagTransport) @@ -266,6 +267,39 @@ func startStandAlone(svrCtx *Context, app types.Application, opts StartCmdOption g, ctx := getCtx(svrCtx, false) + // Add the tx service to the gRPC router. We only need to register this + // service if API or gRPC is enabled, and avoid doing so in the general + // case, because it spawns a new local CometBFT RPC client. + if svrCfg.API.Enable || svrCfg.GRPC.Enable { + // create tendermint client + // assumes the rpc listen address is where tendermint has its rpc server + rpcclient, err := rpchttp.New(svrCtx.Config.RPC.ListenAddress, "/websocket") + if err != nil { + return err + } + // re-assign for making the client available below + // do not use := to avoid shadowing clientCtx + clientCtx = clientCtx.WithClient(rpcclient) + + // use the provided clientCtx to register the services + app.RegisterTxService(clientCtx) + app.RegisterTendermintService(clientCtx) + app.RegisterNodeService(clientCtx, svrCfg) + } + + grpcSrv, clientCtx, err := startGrpcServer(ctx, g, svrCfg.GRPC, clientCtx, svrCtx, app) + if err != nil { + return err + } + + cmtCfg := svrCtx.Config + home := cmtCfg.RootDir + + err = startAPIServer(ctx, g, cmtCfg, svrCfg, clientCtx, svrCtx, app, home, grpcSrv, metrics) + if err != nil { + return err + } + g.Go(func() error { if err := svr.Start(); err != nil { svrCtx.Logger.Error("failed to start out-of-process ABCI server", "err", err)