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 all 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
7 changes: 4 additions & 3 deletions libs/utils/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ func ValidateAddr(addr string) (string, error) {
return addr, nil
}

resolved, err := net.ResolveIPAddr("ip4", addr)
_, err = net.LookupHost(addr)
if err != nil {
return addr, err
return "", err
}
return resolved.String(), nil

return addr, nil
}
6 changes: 0 additions & 6 deletions libs/utils/address_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package utils

import (
"net"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -60,11 +59,6 @@ func TestValidateAddr(t *testing.T) {
got, err := ValidateAddr(tt.addr)
require.NoError(t, err)

// validate that returned value is ip
if ip := net.ParseIP(got); ip == nil {
t.Fatalf("empty ip")
}

if tt.want.unresolved {
// unresolved addr has no addr to compare with
return
Expand Down
109 changes: 95 additions & 14 deletions nodebuilder/core/config.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,91 @@
package core

import (
"errors"
"fmt"
"strconv"

"github.com/celestiaorg/celestia-node/libs/utils"
)

var MetricsEnabled bool
var (
MetricsEnabled bool

// Config combines all configuration fields for managing the relationship with a Core node.
ErrMultipleHostsConfigured = errors.New("multiple hosts configured")
)

const (
DefaultRPCScheme = "http"
DefaultRPCPort = "26657"
DefaultGRPCPort = "9090"
)

// 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 RPCConfig
GRPC GRPCConfig
}

type RPCConfig struct {
Scheme string
Host string
Port string
}

type GRPCConfig struct {
Host string
Port string
// leaving separate to account for TLS
// and secure connections later
}

// 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: RPCConfig{
Scheme: DefaultRPCScheme,
Port: DefaultRPCPort,
},
GRPC: GRPCConfig{
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.
Expand All @@ -32,24 +94,43 @@ func (cfg *Config) Validate() error {
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)

if cfg.RPC.Scheme == "" {
cfg.RPC.Scheme = DefaultRPCScheme
}

rpcHost, err := utils.ValidateAddr(cfg.RPCHost())
if err != nil {
return fmt.Errorf("nodebuilder/core: invalid rpc host: %s", err.Error())
}

cfg.RPC.Host = rpcHost

grpcHost, err := utils.ValidateAddr(cfg.GRPCHost())
if err != nil {
return fmt.Errorf("nodebuilder/core: invalid grpc host: %s", err.Error())
}

cfg.GRPC.Host = grpcHost

_, 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())
}

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() != ""
}
156 changes: 156 additions & 0 deletions nodebuilder/core/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
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: GRPCConfig{
Host: "",
},
IP: "127.0.0.1",
},
expected: "127.0.0.1",
},
{
name: "Use GRPC Host when set",
cfg: &Config{
GRPC: GRPCConfig{
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.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: RPCConfig{
Host: "",
},
IP: "127.0.0.1",
},
expected: "127.0.0.1",
},
{
name: "Use GRPC Host when set",
cfg: &Config{
RPC: RPCConfig{
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: RPCConfig{
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: GRPCConfig{
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: RPCConfig{
Host: "localhost",
},
},
expected: nil,
},
{
name: "Only gRPC Host configured",
cfg: &Config{
GRPC: GRPCConfig{
Host: "localhost",
},
},
expected: nil,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual := tc.cfg.multipleHostsConfigured()
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