diff --git a/cmd/common.go b/cmd/common.go index f01d296a..a3e9140b 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -39,20 +39,29 @@ func addDatabaseFlags(command *cobra.Command) { func addNitroFlags(command *cobra.Command) { // nitro flags command.PersistentFlags().Bool("nitro-run-node-in-process", false, "nitro run node in process") + command.PersistentFlags().String("nitro-rpc-query-rates-file", "", "nitro rpcQueryRatesFile") command.PersistentFlags().String("nitro-pk", "", "nitro pk") command.PersistentFlags().String("nitro-chain-pk", "", "nitro chainPk") - command.PersistentFlags().String("nitro-chain-url", "", "nitro chainUrl") + command.PersistentFlags().String("nitro-chain-url", "ws://127.0.0.1:8545", "nitro chainUrl") command.PersistentFlags().String("nitro-na-address", "", "nitro naAddress") command.PersistentFlags().String("nitro-vpa-address", "", "nitro vpaAddress") command.PersistentFlags().String("nitro-ca-address", "", "nitro caAddress") command.PersistentFlags().Bool("nitro-use-durable-store", false, "nitro useDurableStore") command.PersistentFlags().String("nitro-durable-store-folder", "", "nitro durableStoreFolder") + command.PersistentFlags().Int("nitro-msg-port", 3005, "nitro msgPort") + command.PersistentFlags().Int("nitro-rpc-port", 4005, "nitro rpcPort") + command.PersistentFlags().Int("nitro-ws-msg-port", 5005, "nitro wsMsgPort") + command.PersistentFlags().Uint("nitro-chain-start-block", 0, "nitro chainStartBlock") + command.PersistentFlags().String("nitro-tls-cert-filepath", "", "nitro tlsCertFilepath") + command.PersistentFlags().String("nitro-tls-key-filepath", "", "nitro tlsKeyFilepath") command.PersistentFlags().String("nitro-endpoint", "", "nitro endpoint") + command.PersistentFlags().Bool("nitro-is-secure", false, "nitro isSecure") // nitro flag bindings viper.BindPFlag("nitro.runNodeInProcess", command.PersistentFlags().Lookup("nitro-run-node-in-process")) + viper.BindPFlag("nitro.rpcQueryRatesFile", command.PersistentFlags().Lookup("nitro-rpc-query-rates-file")) viper.BindPFlag("nitro.inProcesssNode.pk", command.PersistentFlags().Lookup("nitro-pk")) viper.BindPFlag("nitro.inProcesssNode.chainPk", command.PersistentFlags().Lookup("nitro-chain-pk")) @@ -62,6 +71,13 @@ func addNitroFlags(command *cobra.Command) { viper.BindPFlag("nitro.inProcesssNode.caAddress", command.PersistentFlags().Lookup("nitro-ca-address")) viper.BindPFlag("nitro.inProcesssNode.useDurableStore", command.PersistentFlags().Lookup("nitro-use-durable-store")) viper.BindPFlag("nitro.inProcesssNode.durableStoreFolder", command.PersistentFlags().Lookup("nitro-durable-store")) + viper.BindPFlag("nitro.inProcesssNode.msgPort", command.PersistentFlags().Lookup("nitro-msg-port")) + viper.BindPFlag("nitro.inProcesssNode.rpcPort", command.PersistentFlags().Lookup("nitro-rpc-port")) + viper.BindPFlag("nitro.inProcesssNode.wsMsgPort", command.PersistentFlags().Lookup("nitro-ws-msg-port")) + viper.BindPFlag("nitro.inProcesssNode.chainStartBlock", command.PersistentFlags().Lookup("nitro-chain-start-block")) + viper.BindPFlag("nitro.inProcesssNode.tlsCertFilepath", command.PersistentFlags().Lookup("nitro-tls-cert-filepath")) + viper.BindPFlag("nitro.inProcesssNode.tlsKeyFilepath", command.PersistentFlags().Lookup("nitro-tls-key-filepath")) viper.BindPFlag("nitro.remoteNode.nitroEndpoint", command.PersistentFlags().Lookup("nitro-endpoint")) + viper.BindPFlag("nitro.remoteNode.isSecure", command.PersistentFlags().Lookup("nitro-is-secure")) } diff --git a/cmd/serve.go b/cmd/serve.go index f7482c74..1ee0ce03 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -17,8 +17,10 @@ package cmd import ( "crypto/tls" + "encoding/json" "errors" "fmt" + "io/fs" "math/big" "net/http" "net/url" @@ -94,48 +96,19 @@ func serve() { var voucherValidator paymentsmanager.VoucherValidator - // TODO: Refactor into a function / subcommand nitroConfig := serverConfig.Nitro if nitroConfig.RunNodeInProcess { log.Info("Running an in-process Nitro node") - nitroNode, err := initNitroNode(&nitroConfig.InProcessNode) - if err != nil { - logWithCommand.Fatal(err) - } - - pm, err := paymentsmanager.NewPaymentsManager(nitroNode) - if err != nil { - logWithCommand.Fatal(err) - } - pm.Start(wg) + pm, nitroRpcServer := initNitroInProcess(wg, nitroConfig) defer pm.Stop() - - // TODO: Read from config file - rpcPort := 4005 - tlsCertFilepath := "" - tlsKeyFilepath := "" - - var cert *tls.Certificate - if tlsCertFilepath != "" && tlsKeyFilepath != "" { - *cert, err = tls.LoadX509KeyPair(tlsCertFilepath, tlsKeyFilepath) - if err != nil { - logWithCommand.Fatal(err) - } - } - - nitroRpcServer, err := initNitroRpcServer(nitroNode, pm, cert, rpcPort) - if err != nil { - logWithCommand.Fatal(err) - } defer nitroRpcServer.Close() - voucherValidator = paymentsmanager.InProcessVoucherValidator{PaymentsManager: pm} + voucherValidator = paymentsmanager.InProcessVoucherValidator{PaymentsManager: *pm} } else { log.Info("Connecting to a remote Nitro node") - // TODO: Read from config file - isSecure := false + isSecure := nitroConfig.RemoteNode.IsSecure nitroRpcClient, err := nitroRpc.NewHttpRpcClient(nitroConfig.RemoteNode.NitroEndpoint, isSecure) if err != nil { logWithCommand.Fatal(err) @@ -145,15 +118,16 @@ func serve() { voucherValidator = nitroRpc.RemoteVoucherValidator{Client: nitroRpcClient} } - // TODO: Read from config file - queryRates := map[string]*big.Int{ - "eth_getBlockByNumber": big.NewInt(50), - "eth_getBlockByHash": big.NewInt(50), - "eth_getStorageAt": big.NewInt(50), - "eth_getLogs": big.NewInt(50), + queryRates, err := readRpcQueryRates(nitroConfig.RpcQueryRatesFile) + if err != nil { + logWithCommand.Fatal(err) } - if err := startServers(server, serverConfig, voucherValidator, queryRates); err != nil { + paymentMiddleware := func(next http.Handler) http.Handler { + return paymentsmanager.HTTPMiddleware(next, voucherValidator, queryRates) + } + + if err := startServers(server, serverConfig, [](func(next http.Handler) http.Handler){paymentMiddleware}); err != nil { logWithCommand.Fatal(err) } graphQL, err := startEthGraphQL(server, serverConfig) @@ -182,8 +156,7 @@ func serve() { server.Stop() } -// TODO: Absorb voucherValidator and queryRates args into existing ones -func startServers(server s.Server, settings *s.Config, voucherValidator paymentsmanager.VoucherValidator, queryRates map[string]*big.Int) error { +func startServers(server s.Server, settings *s.Config, httpMiddlewares [](func(next http.Handler) http.Handler)) error { if settings.IPCEnabled { logWithCommand.Debug("starting up IPC server") _, _, err := srpc.StartIPCEndpoint(settings.IPCEndpoint, server.APIs()) @@ -206,7 +179,7 @@ func startServers(server s.Server, settings *s.Config, voucherValidator payments if settings.HTTPEnabled { logWithCommand.Debug("starting up HTTP server") - _, err := srpc.StartHTTPEndpoint(settings.HTTPEndpoint, server.APIs(), []string{"vdb", "eth", "debug", "net"}, nil, []string{"*"}, rpc.HTTPTimeouts{}, voucherValidator, queryRates) + _, err := srpc.StartHTTPEndpoint(settings.HTTPEndpoint, server.APIs(), []string{"vdb", "eth", "debug", "net"}, nil, []string{"*"}, rpc.HTTPTimeouts{}, httpMiddlewares) if err != nil { return err } @@ -420,16 +393,47 @@ func init() { viper.BindPFlag("validator.everyNthBlock", serveCmd.PersistentFlags().Lookup("validator-every-nth-block")) } +// Initializes an in-process Nitro node, payments manager and a Nitro RPC server +func initNitroInProcess(wg *sync.WaitGroup, nitroConfig *s.NitroConfig) (*paymentsmanager.PaymentsManager, *nitroRpc.RpcServer) { + nitroNode, err := initNitroNode(&nitroConfig.InProcessNode) + if err != nil { + logWithCommand.Fatal(err) + } + + pm, err := paymentsmanager.NewPaymentsManager(nitroNode) + if err != nil { + logWithCommand.Fatal(err) + } + pm.Start(wg) + + tlsCertFilepath := nitroConfig.InProcessNode.TlsCertFilepath + tlsKeyFilepath := nitroConfig.InProcessNode.TlsKeyFilepath + + var cert *tls.Certificate + if tlsCertFilepath != "" && tlsKeyFilepath != "" { + *cert, err = tls.LoadX509KeyPair(tlsCertFilepath, tlsKeyFilepath) + if err != nil { + logWithCommand.Fatal(err) + } + } + + nitroRpcServer, err := initNitroRpcServer(nitroNode, pm, cert, nitroConfig.InProcessNode.RpcPort) + if err != nil { + logWithCommand.Fatal(err) + } + + return &pm, nitroRpcServer +} + // https://github.com/cerc-io/go-nitro/blob/release-v0.1.1-ts-port-0.1.7/internal/node/node.go#L17 func initNitroNode(config *s.InProcessNitroNodeConfig) (*nitroNode.Node, error) { - // TODO: Read from config file pkString := config.Pk useDurableStore := config.UseDurableStore durableStoreFolder := config.DurableStoreFolder - msgPort := 3005 - wsMsgPort := 5005 + msgPort := config.MsgPort + wsMsgPort := config.WsMsgPort chainUrl := config.ChainUrl - chainStartBlock := uint64(0) + chainStartBlock := config.ChainStartBlock chainPk := config.ChainPk naAddress := config.NaAddress vpaAddress := config.VpaAddress @@ -515,3 +519,31 @@ func initNitroRpcServer(node *nitroNode.Node, pm paymentsmanager.PaymentsManager slog.Info("Completed Nitro RPC server initialization") return rpcServer, nil } + +func readRpcQueryRates(filepath string) (map[string]*big.Int, error) { + result := make(map[string]*big.Int) + + if filepath == "" { + logWithCommand.Warn("RPC query rates file path not provided") + return result, nil + } + + jsonFile, err := os.Open(filepath) + defer jsonFile.Close() + + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + logWithCommand.Warn("RPC query rates file does not exist") + return result, nil + } + return nil, err + } + + decoder := json.NewDecoder(jsonFile) + err = decoder.Decode(&result) + if err != nil { + return nil, err + } + + return result, nil +} diff --git a/environments/example.toml b/environments/example.toml index 232ade55..e6bdcf12 100644 --- a/environments/example.toml +++ b/environments/example.toml @@ -34,6 +34,7 @@ [nitro] runNodeInProcess = false # NITRO_RUN_NODE_IN_PROCESS + rpcQueryRatesFile = "environments/rpcQueryRates.json" # NITRO_RPC_QUERY_RATES_FILE [nitro.inProcesssNode] pk = "" # NITRO_PK @@ -44,6 +45,13 @@ caAddress = "" # NITRO_CA_ADDRESS useDurableStore = true # NITRO_USE_DURABLE_STORE durableStoreFolder = "./data/nitronode" # NITRO_DURABLE_STORE_FOLDER + msgPort = 3005 # NITRO_MSG_PORT + rpcPort = 4005 # NITRO_RPC_PORT + wsMsgPort = 5005 # NITRO_WS_MSG_PORT + chainStartBlock = 0 # NITRO_CHAIN_START_BLOCK + tlsCertFilepath = "" # NITRO_TLS_CERT_FILEPATH + tlsKeyFilepath = "" # NITRO_TLS_KEY_FILEPATH [nitro.remoteNode] nitroEndpoint = "127.0.0.1:4005/api/v1" # NITRO_ENDPOINT + isSecure = false # NITRO_IS_SECURE diff --git a/environments/rpcQueryRates.json b/environments/rpcQueryRates.json new file mode 100644 index 00000000..b4cb5775 --- /dev/null +++ b/environments/rpcQueryRates.json @@ -0,0 +1,6 @@ +{ + "eth_getBlockByNumber": 50, + "eth_getBlockByHash": 50, + "eth_getStorageAt": 50, + "eth_getLogs": 50 +} diff --git a/go.mod b/go.mod index 80f9da3e..88fcef73 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.4.0 github.com/spf13/viper v1.11.0 - github.com/statechannels/go-nitro v0.1.1 + github.com/statechannels/go-nitro v0.1.2 golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 gorm.io/driver/postgres v1.3.7 gorm.io/gorm v1.23.5 @@ -302,6 +302,4 @@ replace ( github.com/cerc-io/ipfs-ethdb/v5 => github.com/cerc-io/ipfs-ethdb/v5 v5.0.1-alpha.0.20231013070931-0b1a36562a28 ) -// TODO: Use release -// https://github.com/cerc-io/go-nitro/tree/ts-interop -replace github.com/statechannels/go-nitro v0.1.1 => github.com/cerc-io/go-nitro v0.1.2-ts-port-0.1.8.0.20231018070130-e66ac486a763 +replace github.com/statechannels/go-nitro v0.1.2 => github.com/cerc-io/go-nitro v0.1.2-ts-port-0.1.9 diff --git a/go.sum b/go.sum index 4717645d..13eb3f17 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,8 @@ github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2 github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI= github.com/cerc-io/eth-ipfs-state-validator/v5 v5.1.1-alpha.0.20231013075659-56aa03028c43 h1:pkGCN+VWo5Qmu4iDjA7noGrE6wM8VOVeX1Mn6ucYhPg= github.com/cerc-io/eth-ipfs-state-validator/v5 v5.1.1-alpha.0.20231013075659-56aa03028c43/go.mod h1:snThUFpyCrpZhTuz3HibJRLL2XaS+lKNsM3XAE0gB/4= -github.com/cerc-io/go-nitro v0.1.2-ts-port-0.1.8.0.20231018070130-e66ac486a763 h1:RTUK5AquaGw/aMbdgpDuj0IHhqgAg6R2own9lI14ZOQ= -github.com/cerc-io/go-nitro v0.1.2-ts-port-0.1.8.0.20231018070130-e66ac486a763/go.mod h1:YYQvj9es00ZfLTwxZLM1M0ihUrqz8+lU2c10G06My3A= +github.com/cerc-io/go-nitro v0.1.2-ts-port-0.1.9 h1:Q4hptIWBsSRQ9A16xQuPog2eihhspqwzP1Hm5TvahgA= +github.com/cerc-io/go-nitro v0.1.2-ts-port-0.1.9/go.mod h1:YYQvj9es00ZfLTwxZLM1M0ihUrqz8+lU2c10G06My3A= github.com/cerc-io/ipfs-ethdb/v5 v5.0.1-alpha.0.20231013070931-0b1a36562a28 h1:5FXtMuZXTIXjjzzLdqgyzx9pjD22FB5os2vXayRn+BQ= github.com/cerc-io/ipfs-ethdb/v5 v5.0.1-alpha.0.20231013070931-0b1a36562a28/go.mod h1:W1C6qTXGsPcsK1HKUYPsXmBORjO2ekdm+101sJkpdNI= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= diff --git a/pkg/rpc/http.go b/pkg/rpc/http.go index 02c683c3..42871e77 100644 --- a/pkg/rpc/http.go +++ b/pkg/rpc/http.go @@ -18,20 +18,18 @@ package rpc import ( "fmt" - "math/big" + "net/http" "github.com/cerc-io/ipld-eth-server/v5/pkg/log" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" - "github.com/statechannels/go-nitro/paymentsmanager" "github.com/cerc-io/ipld-eth-server/v5/pkg/prom" ) // StartHTTPEndpoint starts the HTTP RPC endpoint, configured with cors/vhosts/modules. -// TODO: Absorb voucherValidator and queryRates args into existing ones -func StartHTTPEndpoint(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, voucherValidator paymentsmanager.VoucherValidator, queryRates map[string]*big.Int) (*rpc.Server, error) { +func StartHTTPEndpoint(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, httpMiddlewares [](func(next http.Handler) http.Handler)) (*rpc.Server, error) { srv := rpc.NewServer() err := node.RegisterApis(apis, modules, srv) if err != nil { @@ -39,11 +37,16 @@ func StartHTTPEndpoint(endpoint string, apis []rpc.API, modules []string, cors [ } promHandler := prom.HTTPMiddleware(node.NewHTTPHandlerStack(srv, cors, vhosts, nil)) - paymentHandler := paymentsmanager.HTTPMiddleware(promHandler, voucherValidator, queryRates) + + // Chain the HTTP middlewares + handler := promHandler + for _, middleware := range httpMiddlewares { + handler = middleware(handler) + } // start http server // request -> payments -> metrics -> server - _, addr, err := node.StartHTTPEndpoint(endpoint, rpc.DefaultHTTPTimeouts, paymentHandler) + _, addr, err := node.StartHTTPEndpoint(endpoint, rpc.DefaultHTTPTimeouts, handler) if err != nil { utils.Fatalf("Could not start RPC api: %v", err) } diff --git a/pkg/serve/config.go b/pkg/serve/config.go index e1d0f732..0405e9f9 100644 --- a/pkg/serve/config.go +++ b/pkg/serve/config.go @@ -81,6 +81,7 @@ const ( DATABASE_MAX_CONN_LIFETIME = "DATABASE_MAX_CONN_LIFETIME" NITRO_RUN_NODE_IN_PROCESS = "NITRO_RUN_NODE_IN_PROCESS" + NITRO_RPC_QUERY_RATES_FILE = "NITRO_RPC_QUERY_RATES_FILE" NITRO_PK = "NITRO_PK" NITRO_CHAIN_PK = "NITRO_CHAIN_PK" NITRO_CHAIN_URL = "NITRO_CHAIN_URL" @@ -90,6 +91,13 @@ const ( NITRO_USE_DURABLE_STORE = "NITRO_USE_DURABLE_STORE" NITRO_DURABLE_STORE_FOLDER = "NITRO_DURABLE_STORE_FOLDER" NITRO_ENDPOINT = "NITRO_ENDPOINT" + NITRO_IS_SECURE = "NITRO_IS_SECURE" + NITRO_MSG_PORT = "NITRO_MSG_PORT" + NITRO_WS_MSG_PORT = "NITRO_WS_MSG_PORT" + NITRO_RPC_PORT = "NITRO_RPC_PORT" + NITRO_CHAIN_START_BLOCK = "NITRO_CHAIN_START_BLOCK" + NITRO_TLS_CERT_FILEPATH = "NITRO_TLS_CERT_FILEPATH" + NITRO_TLS_KEY_FILEPATH = "NITRO_TLS_KEY_FILEPATH" ) type InProcessNitroNodeConfig struct { @@ -101,16 +109,24 @@ type InProcessNitroNodeConfig struct { CaAddress string UseDurableStore bool DurableStoreFolder string + RpcPort int + MsgPort int + WsMsgPort int + ChainStartBlock uint64 + TlsCertFilepath string + TlsKeyFilepath string } type RemoteNitroNodeConfig struct { NitroEndpoint string + IsSecure bool } type NitroConfig struct { - RunNodeInProcess bool - InProcessNode InProcessNitroNodeConfig - RemoteNode RemoteNitroNodeConfig + RunNodeInProcess bool + RpcQueryRatesFile string + InProcessNode InProcessNitroNodeConfig + RemoteNode RemoteNitroNodeConfig } // Config struct @@ -320,6 +336,7 @@ func (c *Config) loadNitroConfig() { c.Nitro = &NitroConfig{InProcessNode: InProcessNitroNodeConfig{}, RemoteNode: RemoteNitroNodeConfig{}} viper.BindEnv("nitro.runNodeInProcess", NITRO_RUN_NODE_IN_PROCESS) + viper.BindEnv("nitro.rpcQueryRatesFile", NITRO_RPC_QUERY_RATES_FILE) viper.BindEnv("nitro.inProcesssNode.pk", NITRO_PK) viper.BindEnv("nitro.inProcesssNode.chainPk", NITRO_CHAIN_PK) @@ -329,10 +346,18 @@ func (c *Config) loadNitroConfig() { viper.BindEnv("nitro.inProcesssNode.caAddress", NITRO_CA_ADDRESS) viper.BindEnv("nitro.inProcesssNode.useDurableStore", NITRO_USE_DURABLE_STORE) viper.BindEnv("nitro.inProcesssNode.durableStoreFolder", NITRO_DURABLE_STORE_FOLDER) + viper.BindEnv("nitro.inProcesssNode.msgPort", NITRO_MSG_PORT) + viper.BindEnv("nitro.inProcesssNode.rpcPort", NITRO_RPC_PORT) + viper.BindEnv("nitro.inProcesssNode.wsMsgPort", NITRO_WS_MSG_PORT) + viper.BindEnv("nitro.inProcesssNode.chainStartBlock", NITRO_CHAIN_START_BLOCK) + viper.BindEnv("nitro.inProcesssNode.tlsCertFilepath", NITRO_TLS_CERT_FILEPATH) + viper.BindEnv("nitro.inProcesssNode.tlsKeyFilepath", NITRO_TLS_KEY_FILEPATH) viper.BindEnv("nitro.remoteNode.nitroEndpoint", NITRO_ENDPOINT) + viper.BindEnv("nitro.remoteNode.isSecure", NITRO_IS_SECURE) c.Nitro.RunNodeInProcess = viper.GetBool("nitro.runNodeInProcess") + c.Nitro.RpcQueryRatesFile = viper.GetString("nitro.rpcQueryRatesFile") c.Nitro.InProcessNode.Pk = viper.GetString("nitro.inProcesssNode.pk") c.Nitro.InProcessNode.ChainPk = viper.GetString("nitro.inProcesssNode.chainPk") @@ -342,8 +367,15 @@ func (c *Config) loadNitroConfig() { c.Nitro.InProcessNode.CaAddress = viper.GetString("nitro.inProcesssNode.caAddress") c.Nitro.InProcessNode.UseDurableStore = viper.GetBool("nitro.inProcesssNode.useDurableStore") c.Nitro.InProcessNode.DurableStoreFolder = viper.GetString("nitro.inProcesssNode.durableStoreFolder") + c.Nitro.InProcessNode.MsgPort = viper.GetInt("nitro.inProcesssNode.msgPort") + c.Nitro.InProcessNode.RpcPort = viper.GetInt("nitro.inProcesssNode.rpcPort") + c.Nitro.InProcessNode.WsMsgPort = viper.GetInt("nitro.inProcesssNode.wsMsgPort") + c.Nitro.InProcessNode.ChainStartBlock = viper.GetUint64("nitro.inProcesssNode.chainStartBlock") + c.Nitro.InProcessNode.TlsCertFilepath = viper.GetString("nitro.inProcesssNode.tlsCertFilepath") + c.Nitro.InProcessNode.TlsKeyFilepath = viper.GetString("nitro.inProcesssNode.tlsKeyFilepath") c.Nitro.RemoteNode.NitroEndpoint = viper.GetString("nitro.remoteNode.nitroEndpoint") + c.Nitro.RemoteNode.IsSecure = viper.GetBool("nitro.remoteNode.isSecure") } func (c *Config) loadGroupCacheConfig() {