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(modp2p): websocket transport with TLS #3560

Merged
merged 14 commits into from
Aug 6, 2024
1 change: 1 addition & 0 deletions nodebuilder/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func ConstructModule(tp node.Type, network p2p.Network, cfg *Config, store Store
fx.Supply(tp),
fx.Supply(network),
fx.Supply(ks),
fx.Supply(p2p.TLSPath(tlsPath(store.Path()))),
fx.Provide(p2p.BootstrappersFor),
fx.Provide(func(lc fx.Lifecycle) context.Context {
return fxutil.WithLifecycle(context.Background(), lc)
Expand Down
6 changes: 3 additions & 3 deletions nodebuilder/p2p/addrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import (
)

// Listen returns invoke function that starts listening for inbound connections with libp2p.Host.
func Listen(listen []string) func(h hst.Host) (err error) {
func Listen(cfg *Config) func(h hst.Host) (err error) {
return func(h hst.Host) (err error) {
maListen := make([]ma.Multiaddr, len(listen))
for i, addr := range listen {
maListen := make([]ma.Multiaddr, len(cfg.ListenAddresses))
for i, addr := range cfg.ListenAddresses {
maListen[i], err = ma.NewMultiaddr(addr)
if err != nil {
return fmt.Errorf("failure to parse config.P2P.ListenAddresses: %w", err)
Expand Down
22 changes: 21 additions & 1 deletion nodebuilder/p2p/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import (
"github.com/libp2p/go-libp2p/core/routing"
routedhost "github.com/libp2p/go-libp2p/p2p/host/routed"
"github.com/libp2p/go-libp2p/p2p/net/conngater"
quic "github.com/libp2p/go-libp2p/p2p/transport/quic"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
"github.com/prometheus/client_golang/prometheus"
"go.uber.org/fx"

Expand Down Expand Up @@ -79,9 +82,9 @@ func host(params hostParams) (HostBase, error) {
libp2p.DisableRelay(),
libp2p.BandwidthReporter(params.Bandwidth),
libp2p.ResourceManager(params.ResourceManager),
enableTransport(params.Cfg, params.TLS),
// to clearly define what defaults we rely upon
libp2p.DefaultSecurity,
libp2p.DefaultTransports,
libp2p.DefaultMuxers,
}

Expand All @@ -108,11 +111,28 @@ func host(params hostParams) (HostBase, error) {
return h, nil
}

func enableTransport(cfg *Config, tls *tls) libp2p.Option {
options := []libp2p.Option{
libp2p.Transport(tcp.NewTCPTransport),
libp2p.Transport(quic.NewTransport),
libp2p.Transport(webtransport.New),
}

wsTransport := tls.transport()
if wsTransport != nil {
options = append(options, wsTransport)
tls.upgrade(cfg)
}
return libp2p.ChainOptions(options...)
}

type HostBase hst.Host

type hostParams struct {
fx.In

Cfg *Config
TLS *tls
Net Network
Lc fx.Lifecycle
ID peer.ID
Expand Down
2 changes: 1 addition & 1 deletion nodebuilder/p2p/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func defaultConnManagerConfig(tp node.Type) connManagerConfig {
}

// connectionManager provides a constructor for ConnectionManager.
func connectionManager(cfg Config, bpeers Bootstrappers) (connmgri.ConnManager, error) {
func connectionManager(cfg *Config, bpeers Bootstrappers) (connmgri.ConnManager, error) {
fpeers, err := cfg.mutualPeers()
if err != nil {
return nil, err
Expand Down
8 changes: 5 additions & 3 deletions nodebuilder/p2p/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ var log = logging.Logger("module/p2p")
func ConstructModule(tp node.Type, cfg *Config) fx.Option {
// sanitize config values before constructing module
cfgErr := cfg.Validate()

baseComponents := fx.Options(
fx.Supply(*cfg),
fx.Error(cfgErr),
fx.Supply(cfg),
fx.Provide(fx.Annotate(func(path TLSPath) (*tls, error) {
return tlsConfig(string(path))
})),
fx.Provide(Key),
fx.Provide(id),
fx.Provide(peerStore),
Expand All @@ -34,7 +36,7 @@ func ConstructModule(tp node.Type, cfg *Config) fx.Option {
fx.Provide(addrsFactory(cfg.AnnounceAddresses, cfg.NoAnnounceAddresses)),
fx.Provide(metrics.NewBandwidthCounter),
fx.Provide(newModule),
fx.Invoke(Listen(cfg.ListenAddresses)),
fx.Invoke(Listen(cfg)),
fx.Provide(resourceManager),
fx.Provide(resourceManagerOpt(allowList)),
)
Expand Down
1 change: 1 addition & 0 deletions nodebuilder/p2p/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func testModule(tp node.Type) fx.Option {
ConstructModule(tp, &cfg),
fx.Provide(context.Background),
fx.Supply(Private),
fx.Supply(TLSPath("")),
fx.Supply(Bootstrappers{}),
fx.Supply(tp),
fx.Provide(keystore.NewMapKeystore),
Expand Down
4 changes: 2 additions & 2 deletions nodebuilder/p2p/pubsub.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func init() {
}

// pubSub provides a constructor for PubSub protocol with GossipSub routing.
func pubSub(cfg Config, params pubSubParams) (*pubsub.PubSub, error) {
func pubSub(cfg *Config, params pubSubParams) (*pubsub.PubSub, error) {
fpeers, err := cfg.mutualPeers()
if err != nil {
return nil, err
Expand Down Expand Up @@ -122,7 +122,7 @@ func topicScoreParams(params pubSubParams) map[string]*pubsub.TopicScoreParams {
return mp
}

func peerScoreParams(bootstrappers Bootstrappers, cfg Config) (*pubsub.PeerScoreParams, error) {
func peerScoreParams(bootstrappers Bootstrappers, cfg *Config) (*pubsub.PeerScoreParams, error) {
bootstrapperSet := map[peer.ID]struct{}{}
for _, b := range bootstrappers {
bootstrapperSet[b.ID] = struct{}{}
Expand Down
2 changes: 1 addition & 1 deletion nodebuilder/p2p/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func autoscaleResources() rcmgr.ConcreteLimitConfig {
return limits.AutoScale()
}

func allowList(ctx context.Context, cfg Config, bootstrappers Bootstrappers) (rcmgr.Option, error) {
func allowList(ctx context.Context, cfg *Config, bootstrappers Bootstrappers) (rcmgr.Option, error) {
mutual, err := cfg.mutualPeers()
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion nodebuilder/p2p/routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func contentRouting(r routing.PeerRouting) routing.ContentRouting {

// peerRouting provides constructor for PeerRouting over DHT.
// Basically, this provides a way to discover peer addresses by respecting public keys.
func peerRouting(cfg Config, tp node.Type, params routingParams) (routing.PeerRouting, error) {
func peerRouting(cfg *Config, tp node.Type, params routingParams) (routing.PeerRouting, error) {
opts := []dht.Option{
dht.Mode(dht.ModeAuto),
dht.BootstrapPeers(params.Peers...),
Expand Down
73 changes: 73 additions & 0 deletions nodebuilder/p2p/tls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package p2p

import (
cfg "crypto/tls"

"github.com/libp2p/go-libp2p"
ws "github.com/libp2p/go-libp2p/p2p/transport/websocket"

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

const (
cert = "/cert.pem"
key = "/key.pem"
)

// TLSPath is an alias of the file path of TLS certificates and keys.
type TLSPath string

type tls struct {
*cfg.Config
ListenAddresses []string
NoAnnounceAddresses []string
}

func newTLS(path string) (*tls, error) {
var certificates []cfg.Certificate
if path != "" {
cert, err := cfg.LoadX509KeyPair(path+cert, path+key)
if err != nil {
return nil, err
}
certificates = append(certificates, cert)
}
config := &cfg.Config{MinVersion: cfg.VersionTLS12, Certificates: certificates}

return &tls{
Config: config,
ListenAddresses: []string{
"/ip4/0.0.0.0/tcp/2122/wss",
"/ip6/::/tcp/2122/wss",
},
NoAnnounceAddresses: []string{
"/ip4/127.0.0.1/tcp/2122/wss",
"/ip6/::/tcp/2122/wss",
},
}, nil
}

func tlsConfig(path string) (*tls, error) {
exist := utils.Exists(path+cert) && utils.Exists(path+key)
if !exist {
return newTLS("")
}

return newTLS(path)
}

func (tls *tls) upgrade(cfg *Config) {
if len(tls.Certificates) == 0 {
return
}

cfg.ListenAddresses = append(cfg.ListenAddresses, tls.ListenAddresses...)
cfg.NoAnnounceAddresses = append(cfg.NoAnnounceAddresses, tls.NoAnnounceAddresses...)
}

func (tls *tls) transport() libp2p.Option {
if len(tls.Config.Certificates) == 0 {
return nil
}
return libp2p.Transport(ws.New, ws.WithTLSConfig(tls.Config))
}
2 changes: 2 additions & 0 deletions nodebuilder/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ func dataPath(base string) string {
return filepath.Join(base, "data")
}

func tlsPath(base string) string { return filepath.Join(base, "tls") }

// constraintBadgerConfig returns BadgerDB configuration optimized for low memory usage and more frequent
// compaction which prevents memory spikes.
// This is particularly important for LNs with restricted memory resources.
Expand Down
2 changes: 1 addition & 1 deletion state/core_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ func (ca *CoreAccessor) setupTxClient(ctx context.Context, keyName string) (*use
}
ca.defaultSignerAddress = addr
return user.SetupTxClient(ctx, ca.keyring, ca.coreConn, encCfg,
user.WithDefaultAccount(keyName), user.WithDefaultAddress(addr),
user.WithDefaultAccount(keyName),
)
}

Expand Down
Loading