Skip to content

Commit

Permalink
cmd/bootnode: move bootnode to own package
Browse files Browse the repository at this point in the history
  • Loading branch information
corverroos committed Dec 6, 2022
1 parent cb9a968 commit 5b4b595
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 194 deletions.
4 changes: 2 additions & 2 deletions app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import (
"github.com/obolnetwork/charon/app/log"
"github.com/obolnetwork/charon/app/version"
"github.com/obolnetwork/charon/cluster"
"github.com/obolnetwork/charon/cmd"
"github.com/obolnetwork/charon/cmd/bootnode"
"github.com/obolnetwork/charon/core"
"github.com/obolnetwork/charon/core/priority"
"github.com/obolnetwork/charon/p2p"
Expand Down Expand Up @@ -294,7 +294,7 @@ func startBootnode(ctx context.Context, t *testing.T) (string, <-chan error) {

errChan := make(chan error, 1)
go func() {
errChan <- cmd.RunBootnode(ctx, cmd.BootnodeConfig{
errChan <- bootnode.Run(ctx, bootnode.Config{
DataDir: dir,
HTTPAddr: addr,
P2PConfig: p2p.Config{
Expand Down
185 changes: 4 additions & 181 deletions cmd/bootnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,16 @@ package cmd

import (
"context"
"fmt"
"net/http"
"os"
"time"

relaylog "github.com/ipfs/go-log/v2"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/peer"
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/obolnetwork/charon/app/errors"
"github.com/obolnetwork/charon/app/log"
"github.com/obolnetwork/charon/app/version"
"github.com/obolnetwork/charon/app/z"
"github.com/obolnetwork/charon/p2p"
"github.com/obolnetwork/charon/cmd/bootnode"
)

// BootnodeConfig defines the config of the bootnode.
type BootnodeConfig struct {
DataDir string
HTTPAddr string
P2PConfig p2p.Config
LogConfig log.Config
AutoP2PKey bool
P2PRelay bool
MaxResPerPeer int
MaxConns int
RelayLogLevel string
}

func newBootnodeCmd(runFunc func(context.Context, BootnodeConfig) error) *cobra.Command {
var config BootnodeConfig
func newBootnodeCmd(runFunc func(context.Context, bootnode.Config) error) *cobra.Command {
var config bootnode.Config

cmd := &cobra.Command{
Use: "bootnode",
Expand All @@ -78,7 +53,7 @@ func newBootnodeCmd(runFunc func(context.Context, BootnodeConfig) error) *cobra.
return cmd
}

func bindBootnodeFlag(flags *pflag.FlagSet, config *BootnodeConfig) {
func bindBootnodeFlag(flags *pflag.FlagSet, config *bootnode.Config) {
flags.StringVar(&config.HTTPAddr, "bootnode-http-address", "127.0.0.1:3640", "Listening address (ip and port) for the bootnode http server serving runtime ENR")
flags.BoolVar(&config.AutoP2PKey, "auto-p2pkey", true, "Automatically create a p2pkey (ecdsa private key used for p2p authentication and ENR) if none found in data directory")
flags.BoolVar(&config.P2PRelay, "p2p-relay", true, "Enable libp2p tcp host providing circuit relay to charon clusters")
Expand All @@ -88,155 +63,3 @@ func bindBootnodeFlag(flags *pflag.FlagSet, config *BootnodeConfig) {
flags.IntVar(&config.MaxResPerPeer, "max-reservations", 512, "Updates max circuit reservations per peer (each valid for 30min)") // TODO(corver): Align flag name to p2p-max-reservations
flags.IntVar(&config.MaxConns, "p2p-max-connections", 16384, "Libp2p maximum number of peers that can connect to this bootnode.")
}

// RunBootnode starts a p2p-udp discv5 bootnode.
func RunBootnode(ctx context.Context, config BootnodeConfig) error {
ctx, cancel := context.WithCancel(ctx)
defer cancel()

ctx = log.WithTopic(ctx, "bootnode")

version.LogInfo(ctx, "Charon bootnode starting")

key, err := p2p.LoadPrivKey(config.DataDir)
if errors.Is(err, os.ErrNotExist) {
if !config.AutoP2PKey {
return errors.New("charon-enr-private-key not found in data dir (run with --auto-p2pkey to auto generate)")
}

log.Info(ctx, "Automatically creating charon-enr-private-key", z.Str("path", p2p.KeyPath(config.DataDir)))

key, err = p2p.NewSavedPrivKey(config.DataDir)
if err != nil {
return err
}
} else if err != nil {
return err
}

// Setup p2p udp discovery.
localEnode, db, err := p2p.NewLocalEnode(config.P2PConfig, key)
if err != nil {
return errors.Wrap(err, "failed to open enode")
}
defer db.Close()

udpNode, err := p2p.NewUDPNode(ctx, config.P2PConfig, localEnode, key, nil)
if err != nil {
return err
}
defer udpNode.Close()

// Setup p2p tcp relay (async for snappy startup)
var (
p2pErr = make(chan error, 1)
logP2P = func() {}
)

go func() {
if !config.P2PRelay {
log.SetLokiLabels(nil)
return
}

if config.RelayLogLevel != "" {
if err := relaylog.SetLogLevel("relay", config.RelayLogLevel); err != nil {
p2pErr <- errors.Wrap(err, "set relay log level")
return
}
}

// Increase resource limits
limiter := rcmgr.DefaultLimits
limiter.SystemBaseLimit.ConnsInbound = config.MaxConns
limiter.SystemBaseLimit.FD = config.MaxConns
limiter.TransientBaseLimit = limiter.SystemBaseLimit

mgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(limiter.Scale(1<<30, config.MaxConns))) // 1GB Memory
if err != nil {
p2pErr <- errors.Wrap(err, "new resource manager")
}

tcpNode, err := p2p.NewTCPNode(ctx, config.P2PConfig, key, p2p.NewOpenGater(), libp2p.ResourceManager(mgr))
if err != nil {
p2pErr <- errors.Wrap(err, "new tcp node")
return
}

log.SetLokiLabels(map[string]string{
"bootnode_peer": p2p.PeerName(tcpNode.ID()),
})

p2p.RegisterConnectionLogger(tcpNode, nil)

// Reservations are valid for 30min (github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay/constraints.go:14)
relayResources := relay.DefaultResources()
relayResources.Limit.Data = 32 * (1 << 20) // 32MB
relayResources.MaxReservationsPerPeer = config.MaxResPerPeer
relayResources.MaxReservationsPerIP = config.MaxResPerPeer
relayResources.MaxReservations = config.MaxConns
relayResources.MaxCircuits = config.MaxResPerPeer

relayService, err := relay.New(tcpNode, relay.WithResources(relayResources))
if err != nil {
p2pErr <- err
return
}

logP2P = func() {
peers := make(map[peer.ID]bool)
conns := tcpNode.Network().Conns()
for _, conn := range conns {
peers[conn.RemotePeer()] = true
}
log.Info(ctx, "Libp2p TCP open connections",
z.Int("total", len(conns)),
z.Int("peers", len(peers)),
)
}

log.Info(ctx, "Libp2p TCP relay started",
z.Str("peer_name", p2p.PeerName(tcpNode.ID())),
z.Any("p2p_tcp_addr", config.P2PConfig.TCPAddrs),
)

<-ctx.Done()
_ = tcpNode.Close()
_ = relayService.Close()
}()

// Start serving http
serverErr := make(chan error, 1)
go func() {
mux := http.NewServeMux()
mux.HandleFunc("/enr", func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(localEnode.Node().String()))
})
server := http.Server{Addr: config.HTTPAddr, Handler: mux, ReadHeaderTimeout: time.Second}
serverErr <- server.ListenAndServe()
}()

log.Info(ctx, "Discv5 UDP bootnode started",
z.Str("p2p_udp_addr", config.P2PConfig.UDPAddr),
z.Str("enr", localEnode.Node().String()),
)
log.Info(ctx, "Runtime ENR available via http",
z.Str("url", fmt.Sprintf("http://%s/enr", config.HTTPAddr)),
)

ticker := time.NewTicker(time.Minute)
for {
select {
case err := <-serverErr:
return err
case err := <-p2pErr:
return err
case <-ticker.C:
log.Info(ctx, "Discv5 UDP discovered peers", z.Int("peers", len(udpNode.AllNodes())))
logP2P()
case <-ctx.Done():
log.Info(ctx, "Shutting down")
return nil
}
}
}
Loading

0 comments on commit 5b4b595

Please sign in to comment.