Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core/config): enable override of rpc.host and grpc.host, and add ability to use secure connections #3242

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 98 additions & 15 deletions nodebuilder/core/config.go
Original file line number Diff line number Diff line change
@@ -1,55 +1,138 @@
package core

import (
"errors"
"fmt"
"net/url"
"os"
"strconv"
)

var (
MetricsEnabled bool

"github.com/celestiaorg/celestia-node/libs/utils"
ErrMultipleHostsConfigured = errors.New("multiple hosts configured")
)

var MetricsEnabled bool
const (
DefaultRPCScheme = "http"
DefaultRPCPort = "26657"
DefaultGRPCPort = "9090"
)

// Config combines all configuration fields for managing the relationship with a Core node.
// Config combines all configuration fields for
// managing the relationship with a Core node.
type Config struct {
IP string
RPCPort string
GRPCPort string
IP string
RPC HostConfig
GRPC HostConfig
}

type HostConfig struct {
Scheme string
Host string
Port string
Cert string
}

// DefaultConfig returns default configuration for managing the
// node's connection to a Celestia-Core endpoint.
func DefaultConfig() Config {
return Config{
IP: "",
RPCPort: "26657",
GRPCPort: "9090",
IP: "",
RPC: HostConfig{
Scheme: DefaultRPCScheme,
Port: DefaultRPCPort,
},
GRPC: HostConfig{
Scheme: DefaultRPCScheme,
Port: DefaultGRPCPort,
},
}
}

func (cfg *Config) RPCHost() string {
if cfg.RPC.Host != "" {
return cfg.RPC.Host
}
return cfg.IP
}

func (cfg *Config) GRPCHost() string {
if cfg.GRPC.Host != "" {
return cfg.GRPC.Host
}
return cfg.IP
}

func (cfg *Config) multipleHostsConfigured() error {
if cfg.IP != "" && cfg.RPC.Host != "" {
return fmt.Errorf(
"%w: core.ip overridden by core.rpc.host",
ErrMultipleHostsConfigured,
)
}

if cfg.IP != "" && cfg.GRPC.Host != "" {
return fmt.Errorf(
"%w: core.ip overridden by core.grpc.host",
ErrMultipleHostsConfigured,
)
}

return nil
}

// Validate performs basic validation of the config.
func (cfg *Config) Validate() error {
if !cfg.IsEndpointConfigured() {
return nil
}

ip, err := utils.ValidateAddr(cfg.IP)
if err != nil {
if err := cfg.multipleHostsConfigured(); err != nil {
return err
}
cfg.IP = ip
_, err = strconv.Atoi(cfg.RPCPort)

rpcURL, err := url.Parse(cfg.RPCHost())
if err != nil {
return fmt.Errorf("nodebuilder/core: invalid rpc host: %s", err.Error())
}
cfg.RPC.Host = rpcURL.Host

if rpcURL.Scheme != "" {
cfg.RPC.Scheme = rpcURL.Scheme
}

grpcURL, err := url.Parse(cfg.GRPCHost())
if err != nil {
return fmt.Errorf("nodebuilder/core: invalid grpc host: %s", err.Error())
}
cfg.GRPC.Host = grpcURL.Host

if grpcURL.Scheme != "" {
cfg.GRPC.Scheme = rpcURL.Scheme
}

_, err = strconv.Atoi(cfg.RPC.Port)
if err != nil {
return fmt.Errorf("nodebuilder/core: invalid rpc port: %s", err.Error())
}
_, err = strconv.Atoi(cfg.GRPCPort)
_, err = strconv.Atoi(cfg.GRPC.Port)
if err != nil {
return fmt.Errorf("nodebuilder/core: invalid grpc port: %s", err.Error())
}

if cfg.GRPC.Cert != "" {
if _, err := os.Stat(cfg.GRPC.Cert); os.IsNotExist(err) {
return fmt.Errorf("nodebuilder/core: grpc cert file does not exist: %s", cfg.GRPC.Cert)
}
}

return nil
}

// IsEndpointConfigured returns whether a core endpoint has been set
// on the config (true if set).
func (cfg *Config) IsEndpointConfigured() bool {
return cfg.IP != ""
return cfg.RPCHost() != "" && cfg.GRPCHost() != ""
}
159 changes: 159 additions & 0 deletions nodebuilder/core/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package core

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)

func TestDefaultValues(t *testing.T) {
expectedRPCScheme := "http"
expectedRPCPort := "26657"
expectedGRPCPort := "9090"

assert.Equal(t, expectedRPCScheme, DefaultRPCScheme, "DefaultRPCScheme is incorrect")
assert.Equal(t, expectedRPCPort, DefaultRPCPort, "DefaultRPCPort is incorrect")
assert.Equal(t, expectedGRPCPort, DefaultGRPCPort, "DefaultGRPCPort is incorrect")
}

func TestGRPCHost(t *testing.T) {
testCases := []struct {
name string
cfg *Config
expected string
}{
{
name: "Fallback to IP when GRPC Host is not set",
cfg: &Config{
GRPC: HostConfig{
Host: "",
},
IP: "127.0.0.1",
},
expected: "127.0.0.1",
},
{
name: "Use GRPC Host when set",
cfg: &Config{
GRPC: HostConfig{
Host: "0.0.0.0",
},
IP: "127.0.0.1",
},
expected: "0.0.0.0",
},
// Add more test cases here if needed
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual := tc.cfg.GRPCHost()
assert.Equal(t, tc.expected, actual)
})
}
}

func TestRPCHost(t *testing.T) {
testCases := []struct {
name string
cfg *Config
expected string
}{
{
name: "Fallback to IP when GRPC Host is not set",
cfg: &Config{
RPC: HostConfig{
Host: "",
},
IP: "127.0.0.1",
},
expected: "127.0.0.1",
},
{
name: "Use GRPC Host when set",
cfg: &Config{
RPC: HostConfig{
Host: "0.0.0.0",
},
IP: "127.0.0.1",
},
expected: "0.0.0.0",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual := tc.cfg.RPCHost()
assert.Equal(t, tc.expected, actual)
})
}
}

func TestMultipleHostsConfigured(t *testing.T) {
testCases := []struct {
name string
cfg *Config
expected error
}{
{
name: "IP and RPC Host both configured",
cfg: &Config{
IP: "127.0.0.1",
RPC: HostConfig{
Host: "localhost",
},
},
expected: fmt.Errorf("multiple hosts configured: core.ip overridden by core.rpc.host"),
},
{
name: "IP and gRPC Host both configured",
cfg: &Config{
IP: "127.0.0.1",
GRPC: HostConfig{
Host: "localhost",
},
},
expected: fmt.Errorf("multiple hosts configured: core.ip overridden by core.grpc.host"),
},
{
name: "Only IP configured",
cfg: &Config{
IP: "127.0.0.1",
},
expected: nil,
},
{
name: "Only RPC Host configured",
cfg: &Config{
RPC: HostConfig{
Host: "localhost",
},
},
expected: nil,
},
{
name: "Only gRPC Host configured",
cfg: &Config{
GRPC: HostConfig{
Host: "localhost",
},
},
expected: nil,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual := tc.cfg.multipleHostsConfigured()
fmt.Println(actual)
fmt.Println(tc.expected)
if tc.expected == nil {
assert.Nil(t, actual)
} else {
assert.Error(t, actual)
assert.EqualError(t, actual, tc.expected.Error())
}
})
}
}
2 changes: 1 addition & 1 deletion nodebuilder/core/constructors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import (
)

func remote(cfg Config) (core.Client, error) {
return core.NewRemote(cfg.IP, cfg.RPCPort)
return core.NewRemote(cfg.RPCHost(), cfg.RPC.Port)
}
Loading
Loading