2023-07-06 21:40:57 +00:00
|
|
|
package main
|
2021-03-18 23:21:45 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-10-04 22:38:27 +00:00
|
|
|
"crypto/ecdsa"
|
2021-04-19 00:03:16 +00:00
|
|
|
"database/sql"
|
2022-07-25 12:24:42 +00:00
|
|
|
"encoding/json"
|
2021-03-18 23:21:45 +00:00
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"os/signal"
|
2022-12-07 17:34:56 +00:00
|
|
|
"sync"
|
2021-03-18 23:21:45 +00:00
|
|
|
"syscall"
|
2021-06-24 13:02:53 +00:00
|
|
|
"time"
|
2021-03-18 23:21:45 +00:00
|
|
|
|
2023-05-24 15:34:35 +00:00
|
|
|
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
|
|
|
|
"github.com/pbnjay/memory"
|
2023-08-16 01:40:00 +00:00
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
2023-10-18 19:21:37 +00:00
|
|
|
"github.com/urfave/cli/v2"
|
2023-05-24 15:34:35 +00:00
|
|
|
|
2023-07-06 21:40:57 +00:00
|
|
|
dbutils "github.com/waku-org/go-waku/waku/persistence/utils"
|
2023-11-13 12:17:43 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/dnsdisc"
|
2023-08-03 16:21:15 +00:00
|
|
|
wakupeerstore "github.com/waku-org/go-waku/waku/v2/peerstore"
|
2023-03-09 15:48:25 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/rendezvous"
|
2022-11-25 21:24:34 +00:00
|
|
|
|
2022-07-25 12:24:42 +00:00
|
|
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
2021-03-23 14:46:16 +00:00
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
2021-04-13 18:54:06 +00:00
|
|
|
dssql "github.com/ipfs/go-ds-sql"
|
2022-01-18 18:17:06 +00:00
|
|
|
"go.uber.org/zap"
|
2023-02-01 23:35:31 +00:00
|
|
|
"go.uber.org/zap/zapcore"
|
2021-10-03 21:45:07 +00:00
|
|
|
|
2021-04-13 18:54:06 +00:00
|
|
|
"github.com/libp2p/go-libp2p"
|
2021-10-15 02:15:02 +00:00
|
|
|
"github.com/libp2p/go-libp2p/config"
|
2022-10-19 19:39:32 +00:00
|
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
2023-02-16 16:17:52 +00:00
|
|
|
"github.com/libp2p/go-libp2p/core/protocol"
|
2022-08-25 20:36:04 +00:00
|
|
|
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
|
2021-10-04 22:38:27 +00:00
|
|
|
|
2021-10-08 13:50:56 +00:00
|
|
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
2024-01-12 17:40:27 +00:00
|
|
|
"github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoreds" // nolint: staticcheck
|
2022-08-25 20:36:04 +00:00
|
|
|
ws "github.com/libp2p/go-libp2p/p2p/transport/websocket"
|
2021-04-22 13:07:22 +00:00
|
|
|
"github.com/multiformats/go-multiaddr"
|
2023-09-07 18:00:59 +00:00
|
|
|
"github.com/waku-org/go-waku/cmd/waku/server/rest"
|
2022-11-09 19:53:01 +00:00
|
|
|
"github.com/waku-org/go-waku/logging"
|
|
|
|
"github.com/waku-org/go-waku/waku/metrics"
|
|
|
|
"github.com/waku-org/go-waku/waku/persistence"
|
|
|
|
"github.com/waku-org/go-waku/waku/v2/node"
|
2023-09-06 04:37:21 +00:00
|
|
|
wprotocol "github.com/waku-org/go-waku/waku/v2/protocol"
|
2022-11-09 19:53:01 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/filter"
|
2024-05-03 16:07:03 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/legacy_store"
|
2022-11-09 19:53:01 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/lightpush"
|
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/peer_exchange"
|
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/relay"
|
|
|
|
"github.com/waku-org/go-waku/waku/v2/utils"
|
2024-01-03 01:36:41 +00:00
|
|
|
|
|
|
|
humanize "github.com/dustin/go-humanize"
|
2021-03-18 23:21:45 +00:00
|
|
|
)
|
|
|
|
|
2023-08-09 18:14:54 +00:00
|
|
|
func requiresDB(options NodeOptions) bool {
|
2023-07-27 17:04:08 +00:00
|
|
|
return options.Store.Enable || options.Rendezvous.Enable
|
2023-03-09 15:48:25 +00:00
|
|
|
}
|
|
|
|
|
2023-05-24 15:34:35 +00:00
|
|
|
func scalePerc(value float64) float64 {
|
|
|
|
if value > 100 {
|
|
|
|
return 100
|
|
|
|
}
|
|
|
|
|
|
|
|
if value < 0.1 {
|
|
|
|
return 0.1
|
|
|
|
}
|
|
|
|
|
|
|
|
return value
|
|
|
|
}
|
|
|
|
|
2022-08-26 00:18:03 +00:00
|
|
|
const dialTimeout = 7 * time.Second
|
|
|
|
|
2023-10-18 19:21:37 +00:00
|
|
|
func nonRecoverErrorMsg(format string, a ...any) error {
|
|
|
|
err := fmt.Errorf(format, a...)
|
|
|
|
return nonRecoverError(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func nonRecoverError(err error) error {
|
|
|
|
return cli.Exit(err.Error(), 166)
|
|
|
|
}
|
|
|
|
|
2021-10-09 18:18:53 +00:00
|
|
|
// Execute starts a go-waku node with settings determined by the Options parameter
|
2023-10-18 19:21:37 +00:00
|
|
|
func Execute(options NodeOptions) error {
|
2023-08-19 03:18:42 +00:00
|
|
|
// Set encoding for logs (console, json, ...)
|
|
|
|
// Note that libp2p reads the encoding from GOLOG_LOG_FMT env var.
|
2024-08-19 09:30:15 +00:00
|
|
|
lvl, err := zapcore.ParseLevel(options.LogLevel)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
utils.InitLogger(options.LogEncoding, options.LogOutput, "gowaku", lvl)
|
2023-08-19 03:18:42 +00:00
|
|
|
|
2021-10-15 02:15:02 +00:00
|
|
|
hostAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", options.Address, options.Port))
|
2023-10-18 19:21:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nonRecoverErrorMsg("invalid host address: %w", err)
|
|
|
|
}
|
2021-03-18 23:21:45 +00:00
|
|
|
|
2021-10-04 22:38:27 +00:00
|
|
|
prvKey, err := getPrivKey(options)
|
2023-10-18 19:21:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-04-13 18:54:06 +00:00
|
|
|
|
2022-05-27 19:55:35 +00:00
|
|
|
p2pPrvKey := utils.EcdsaPrivKeyToSecp256k1PrivKey(prvKey)
|
|
|
|
id, err := peer.IDFromPublicKey(p2pPrvKey.GetPublic())
|
2023-10-18 19:21:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-05-27 13:25:06 +00:00
|
|
|
logger := utils.Logger().With(logging.HostID("node", id))
|
|
|
|
|
2021-10-03 21:45:07 +00:00
|
|
|
var db *sql.DB
|
2024-01-03 16:49:54 +00:00
|
|
|
var migrationFn func(*sql.DB, *zap.Logger) error
|
2023-08-08 15:46:32 +00:00
|
|
|
if requiresDB(options) && options.Store.Migration {
|
2023-11-09 20:10:40 +00:00
|
|
|
dbSettings := dbutils.DBSettings{}
|
2024-01-02 16:35:58 +00:00
|
|
|
db, migrationFn, err = dbutils.ParseURL(options.Store.DatabaseURL, dbSettings, logger)
|
2023-10-18 19:21:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nonRecoverErrorMsg("could not connect to DB: %w", err)
|
|
|
|
}
|
2021-10-03 21:45:07 +00:00
|
|
|
}
|
2021-04-22 13:07:22 +00:00
|
|
|
|
2021-10-03 21:45:07 +00:00
|
|
|
ctx := context.Background()
|
2021-04-19 00:03:16 +00:00
|
|
|
|
2021-10-03 21:45:07 +00:00
|
|
|
var metricsServer *metrics.Server
|
|
|
|
if options.Metrics.Enable {
|
2022-05-30 15:55:30 +00:00
|
|
|
metricsServer = metrics.NewMetricsServer(options.Metrics.Address, options.Metrics.Port, logger)
|
2021-10-03 21:45:07 +00:00
|
|
|
go metricsServer.Start()
|
|
|
|
}
|
2021-04-19 00:03:16 +00:00
|
|
|
|
2021-10-03 21:45:07 +00:00
|
|
|
nodeOpts := []node.WakuNodeOption{
|
2022-05-27 13:25:06 +00:00
|
|
|
node.WithLogger(logger),
|
2023-02-01 23:35:31 +00:00
|
|
|
node.WithLogLevel(lvl),
|
2021-10-03 21:45:07 +00:00
|
|
|
node.WithPrivateKey(prvKey),
|
2021-11-17 16:19:42 +00:00
|
|
|
node.WithHostAddress(hostAddr),
|
2024-07-11 16:02:52 +00:00
|
|
|
node.WithKeepAlive(10*time.Second, options.KeepAlive),
|
2023-08-03 16:21:15 +00:00
|
|
|
node.WithMaxPeerConnections(options.MaxPeerConnections),
|
2023-08-16 01:40:00 +00:00
|
|
|
node.WithPrometheusRegisterer(prometheus.DefaultRegisterer),
|
2023-09-27 06:46:37 +00:00
|
|
|
node.WithPeerStoreCapacity(options.PeerStoreCapacity),
|
2024-01-08 19:05:21 +00:00
|
|
|
node.WithMaxConnectionsPerIP(options.IPColocationLimit),
|
2023-10-15 19:16:40 +00:00
|
|
|
node.WithClusterID(uint16(options.ClusterID)),
|
2021-10-03 21:45:07 +00:00
|
|
|
}
|
2023-02-08 16:02:06 +00:00
|
|
|
if len(options.AdvertiseAddresses) != 0 {
|
|
|
|
nodeOpts = append(nodeOpts, node.WithAdvertiseAddresses(options.AdvertiseAddresses...))
|
2022-03-22 00:48:46 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 15:19:44 +00:00
|
|
|
if options.ExtIP != "" {
|
|
|
|
ip := net.ParseIP(options.ExtIP)
|
|
|
|
if ip == nil {
|
2023-10-18 19:21:37 +00:00
|
|
|
return nonRecoverErrorMsg("could not set external IP address: invalid IP")
|
2023-05-08 15:19:44 +00:00
|
|
|
}
|
2023-10-18 19:21:37 +00:00
|
|
|
|
2023-05-08 15:19:44 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithExternalIP(ip))
|
|
|
|
}
|
|
|
|
|
2023-07-06 21:40:57 +00:00
|
|
|
if options.DNS4DomainName != "" {
|
2023-09-11 14:24:05 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithDNS4Domain(options.DNS4DomainName))
|
2023-05-15 15:49:51 +00:00
|
|
|
}
|
|
|
|
|
2022-03-22 13:12:58 +00:00
|
|
|
libp2pOpts := node.DefaultLibP2POptions
|
2023-05-24 15:34:35 +00:00
|
|
|
|
2023-08-16 01:40:00 +00:00
|
|
|
libp2pOpts = append(libp2pOpts, libp2p.PrometheusRegisterer(prometheus.DefaultRegisterer))
|
|
|
|
|
2023-05-24 15:34:35 +00:00
|
|
|
memPerc := scalePerc(options.ResourceScalingMemoryPercent)
|
|
|
|
fdPerc := scalePerc(options.ResourceScalingFDPercent)
|
|
|
|
limits := rcmgr.DefaultLimits // Default memory limit: 1/8th of total memory, minimum 128MB, maximum 1GB
|
|
|
|
scaledLimits := limits.Scale(int64(float64(memory.TotalMemory())*memPerc/100), int(float64(getNumFDs())*fdPerc/100))
|
|
|
|
resourceManager, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(scaledLimits))
|
2023-10-18 19:21:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not set resource limits: %w", err)
|
|
|
|
}
|
2023-05-24 15:34:35 +00:00
|
|
|
|
|
|
|
libp2pOpts = append(libp2pOpts, libp2p.ResourceManager(resourceManager))
|
|
|
|
libp2p.SetDefaultServiceLimits(&limits)
|
|
|
|
|
2023-02-08 16:02:06 +00:00
|
|
|
if len(options.AdvertiseAddresses) == 0 {
|
2022-03-22 13:12:58 +00:00
|
|
|
libp2pOpts = append(libp2pOpts, libp2p.NATPortMap()) // Attempt to open ports using uPNP for NATed hosts.)
|
|
|
|
}
|
|
|
|
|
2023-05-12 21:52:42 +00:00
|
|
|
// Node can be a circuit relay server
|
|
|
|
if options.CircuitRelay {
|
|
|
|
libp2pOpts = append(libp2pOpts, libp2p.EnableRelayService())
|
|
|
|
}
|
|
|
|
|
2023-09-28 20:08:40 +00:00
|
|
|
if options.ForceReachability != "" {
|
|
|
|
libp2pOpts = append(libp2pOpts, libp2p.EnableRelay())
|
2023-09-20 06:54:16 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithCircuitRelayParams(2*time.Second, 2*time.Second))
|
2023-09-28 20:08:40 +00:00
|
|
|
if options.ForceReachability == "private" {
|
|
|
|
logger.Warn("node forced to be unreachable!")
|
|
|
|
libp2pOpts = append(libp2pOpts, libp2p.ForceReachabilityPrivate())
|
|
|
|
} else if options.ForceReachability == "public" {
|
|
|
|
logger.Warn("node forced to be publicly reachable!")
|
|
|
|
libp2pOpts = append(libp2pOpts, libp2p.ForceReachabilityPublic())
|
|
|
|
} else {
|
2023-10-18 19:21:37 +00:00
|
|
|
return nonRecoverErrorMsg("invalid reachability value")
|
2023-09-28 20:08:40 +00:00
|
|
|
}
|
2023-09-20 06:54:16 +00:00
|
|
|
}
|
|
|
|
|
2022-10-26 13:28:28 +00:00
|
|
|
if options.UserAgent != "" {
|
|
|
|
libp2pOpts = append(libp2pOpts, libp2p.UserAgent(options.UserAgent))
|
|
|
|
}
|
|
|
|
|
2022-03-22 13:12:58 +00:00
|
|
|
if options.Websocket.Enable {
|
2022-08-25 20:36:04 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithWebsockets(options.Websocket.Address, options.Websocket.WSPort))
|
2022-03-22 13:12:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if options.Websocket.Secure {
|
2022-08-25 20:36:04 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithSecureWebsockets(options.Websocket.Address, options.Websocket.WSSPort, options.Websocket.CertPath, options.Websocket.KeyPath))
|
2021-10-03 21:45:07 +00:00
|
|
|
}
|
2021-04-19 00:03:16 +00:00
|
|
|
|
2021-10-14 18:17:01 +00:00
|
|
|
if options.ShowAddresses {
|
2021-10-15 02:15:02 +00:00
|
|
|
printListeningAddresses(ctx, nodeOpts, options)
|
2023-10-18 19:21:37 +00:00
|
|
|
return nil
|
2021-10-14 18:17:01 +00:00
|
|
|
}
|
|
|
|
|
2022-11-25 20:54:11 +00:00
|
|
|
if options.Store.Enable && options.PersistPeers {
|
|
|
|
// Create persistent peerstore
|
2023-10-05 00:20:02 +00:00
|
|
|
queries, err := dbutils.NewQueries("peerstore", db)
|
2023-10-18 19:21:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nonRecoverErrorMsg("could not setup persistent peerstore database: %w", err)
|
|
|
|
|
|
|
|
}
|
2021-10-01 17:43:03 +00:00
|
|
|
|
2022-11-25 20:54:11 +00:00
|
|
|
datastore := dssql.NewDatastore(db, queries)
|
|
|
|
opts := pstoreds.DefaultOpts()
|
|
|
|
peerStore, err := pstoreds.NewPeerstore(ctx, datastore, opts)
|
2023-10-18 19:21:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nonRecoverErrorMsg("could not create persistent peerstore: %w", err)
|
|
|
|
}
|
2021-10-01 17:43:03 +00:00
|
|
|
|
2023-06-05 14:39:38 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithPeerStore(peerStore))
|
2021-10-03 21:45:07 +00:00
|
|
|
}
|
2021-03-18 23:21:45 +00:00
|
|
|
|
2021-10-03 21:45:07 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithLibP2POptions(libp2pOpts...))
|
2022-12-09 03:08:04 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithNTP())
|
2021-10-01 17:49:50 +00:00
|
|
|
|
2024-01-03 01:36:41 +00:00
|
|
|
maxMsgSize := parseMsgSizeConfig(options.Relay.MaxMsgSize)
|
|
|
|
|
2022-02-21 15:23:52 +00:00
|
|
|
if options.Relay.Enable {
|
2021-10-03 21:45:07 +00:00
|
|
|
var wakurelayopts []pubsub.Option
|
|
|
|
wakurelayopts = append(wakurelayopts, pubsub.WithPeerExchange(options.Relay.PeerExchange))
|
2024-01-03 01:36:41 +00:00
|
|
|
wakurelayopts = append(wakurelayopts, pubsub.WithMaxMessageSize(maxMsgSize))
|
|
|
|
|
2021-12-06 08:43:00 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithWakuRelayAndMinPeers(options.Relay.MinRelayPeersToPublish, wakurelayopts...))
|
2024-01-03 01:36:41 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithMaxMsgSize(maxMsgSize))
|
2021-10-03 21:45:07 +00:00
|
|
|
}
|
2021-06-10 12:59:51 +00:00
|
|
|
|
2023-04-13 19:28:46 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithWakuFilterLightNode())
|
|
|
|
|
2021-10-03 21:45:07 +00:00
|
|
|
if options.Filter.Enable {
|
2023-04-13 19:28:46 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithWakuFilterFullNode(filter.WithTimeout(options.Filter.Timeout)))
|
|
|
|
}
|
|
|
|
|
2023-03-09 15:48:25 +00:00
|
|
|
var dbStore *persistence.DBStore
|
|
|
|
if requiresDB(options) {
|
2023-08-08 15:46:32 +00:00
|
|
|
dbOptions := []persistence.DBOption{
|
2023-01-04 17:58:14 +00:00
|
|
|
persistence.WithDB(db),
|
|
|
|
persistence.WithRetentionPolicy(options.Store.RetentionMaxMessages, options.Store.RetentionTime),
|
2023-08-08 15:46:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if options.Store.Migration {
|
|
|
|
dbOptions = append(dbOptions, persistence.WithMigrations(migrationFn)) // TODO: refactor migrations out of DBStore, or merge DBStore with rendezvous DB
|
|
|
|
}
|
|
|
|
|
2023-08-16 01:40:00 +00:00
|
|
|
dbStore, err = persistence.NewDBStore(prometheus.DefaultRegisterer, logger, dbOptions...)
|
2023-10-18 19:21:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nonRecoverErrorMsg("error setting up db store: %w", err)
|
|
|
|
}
|
|
|
|
|
2022-09-12 19:58:15 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithMessageProvider(dbStore))
|
2021-10-03 21:45:07 +00:00
|
|
|
}
|
2021-09-30 16:01:53 +00:00
|
|
|
|
2023-03-09 15:48:25 +00:00
|
|
|
if options.Store.Enable {
|
2023-07-15 16:09:00 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithWakuStore())
|
2023-03-09 15:48:25 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithMessageProvider(dbStore))
|
|
|
|
}
|
|
|
|
|
2021-10-03 21:45:07 +00:00
|
|
|
if options.LightPush.Enable {
|
|
|
|
nodeOpts = append(nodeOpts, node.WithLightPush())
|
|
|
|
}
|
2021-04-12 17:59:41 +00:00
|
|
|
|
2022-10-23 13:13:43 +00:00
|
|
|
if options.PeerExchange.Enable {
|
|
|
|
nodeOpts = append(nodeOpts, node.WithPeerExchange())
|
|
|
|
}
|
|
|
|
|
2023-03-09 15:48:25 +00:00
|
|
|
if options.Rendezvous.Enable {
|
2023-09-11 14:24:05 +00:00
|
|
|
rdb := rendezvous.NewDB(db, logger)
|
2023-07-27 17:04:08 +00:00
|
|
|
nodeOpts = append(nodeOpts, node.WithRendezvous(rdb))
|
2023-03-09 15:48:25 +00:00
|
|
|
}
|
|
|
|
|
2023-10-18 19:21:37 +00:00
|
|
|
utils.Logger().Info("Version details ", zap.String("version", node.Version), zap.String("commit", node.GitCommit))
|
2022-07-05 21:28:34 +00:00
|
|
|
|
2023-10-18 19:21:37 +00:00
|
|
|
if err = checkForRLN(logger, options, &nodeOpts); err != nil {
|
|
|
|
return nonRecoverError(err)
|
|
|
|
}
|
2021-04-15 21:23:07 +00:00
|
|
|
|
2023-11-14 11:17:49 +00:00
|
|
|
var discoveredNodes []dnsdisc.DiscoveredNode
|
|
|
|
if options.DNSDiscovery.Enable {
|
|
|
|
if len(options.DNSDiscovery.URLs.Value()) == 0 {
|
|
|
|
return nonRecoverErrorMsg("DNS discovery URL is required")
|
|
|
|
}
|
|
|
|
discoveredNodes = node.GetNodesFromDNSDiscovery(logger, ctx, options.DNSDiscovery.Nameserver, options.DNSDiscovery.URLs.Value())
|
|
|
|
}
|
|
|
|
if options.DiscV5.Enable {
|
|
|
|
discv5Opts, err := node.GetDiscv5Option(discoveredNodes, options.DiscV5.Nodes.Value(), options.DiscV5.Port, options.DiscV5.AutoUpdate)
|
|
|
|
if err != nil {
|
|
|
|
logger.Fatal("parsing ENR", zap.Error(err))
|
|
|
|
}
|
|
|
|
nodeOpts = append(nodeOpts, discv5Opts)
|
|
|
|
}
|
|
|
|
|
2023-09-14 15:00:06 +00:00
|
|
|
//Process pubSub and contentTopics specified and arrive at all corresponding pubSubTopics
|
2023-10-18 19:21:37 +00:00
|
|
|
pubSubTopicMap, err := processTopics(options)
|
|
|
|
if err != nil {
|
|
|
|
return nonRecoverError(err)
|
|
|
|
}
|
|
|
|
|
2023-09-14 15:00:06 +00:00
|
|
|
pubSubTopicMapKeys := make([]string, 0, len(pubSubTopicMap))
|
|
|
|
for k := range pubSubTopicMap {
|
|
|
|
pubSubTopicMapKeys = append(pubSubTopicMapKeys, k)
|
|
|
|
}
|
2021-09-30 16:01:53 +00:00
|
|
|
|
2024-11-22 13:36:02 +00:00
|
|
|
rs, err := wprotocol.TopicsToRelayShards(pubSubTopicMapKeys...)
|
|
|
|
if err == nil {
|
|
|
|
if len(rs) == 1 {
|
|
|
|
nodeOpts = append(nodeOpts, node.WithShards(rs[0].ShardIDs))
|
|
|
|
} else {
|
|
|
|
logger.Warn("could not set ENR shard info", zap.String("error", "invalid number of clusters found"), zap.Int("numClusters", len(rs)))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
logger.Warn("could not obtain list of shards", zap.Error(err))
|
|
|
|
}
|
|
|
|
|
|
|
|
wakuNode, err := node.New(nodeOpts...)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not instantiate waku: %w", err)
|
|
|
|
}
|
|
|
|
|
2023-01-06 22:37:57 +00:00
|
|
|
if err = wakuNode.Start(ctx); err != nil {
|
2023-10-18 19:21:37 +00:00
|
|
|
return nonRecoverError(err)
|
2021-10-06 15:42:57 +00:00
|
|
|
}
|
2021-10-05 02:13:54 +00:00
|
|
|
|
2023-06-05 14:39:38 +00:00
|
|
|
for _, d := range discoveredNodes {
|
2024-05-28 12:50:47 +00:00
|
|
|
wakuNode.AddDiscoveredPeer(d.PeerID, d.PeerInfo.Addrs, wakupeerstore.DNSDiscovery, nil, d.ENR, true)
|
2023-06-05 14:39:38 +00:00
|
|
|
}
|
|
|
|
|
2023-09-14 15:00:06 +00:00
|
|
|
//For now assuming that static peers added support/listen on all topics specified via commandLine.
|
2023-10-18 19:21:37 +00:00
|
|
|
staticPeers := map[protocol.ID][]multiaddr.Multiaddr{
|
2024-05-03 16:07:03 +00:00
|
|
|
legacy_store.StoreID_v20beta4: options.Store.Nodes,
|
2023-10-18 19:21:37 +00:00
|
|
|
lightpush.LightPushID_v20beta1: options.LightPush.Nodes,
|
|
|
|
rendezvous.RendezvousID: options.Rendezvous.Nodes,
|
|
|
|
filter.FilterSubscribeID_v20beta1: options.Filter.Nodes,
|
|
|
|
}
|
|
|
|
for protocolID, peers := range staticPeers {
|
|
|
|
if err = addStaticPeers(wakuNode, peers, pubSubTopicMapKeys, protocolID); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2023-06-01 12:26:03 +00:00
|
|
|
|
2023-07-27 17:04:08 +00:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
2022-02-21 15:23:52 +00:00
|
|
|
if options.Relay.Enable {
|
2023-11-03 13:47:15 +00:00
|
|
|
if err = handleRelayTopics(ctx, &wg, wakuNode, pubSubTopicMap); err != nil {
|
|
|
|
return err
|
2023-05-02 15:10:45 +00:00
|
|
|
}
|
2021-10-03 21:45:07 +00:00
|
|
|
}
|
2021-03-18 23:21:45 +00:00
|
|
|
|
2022-08-15 17:13:45 +00:00
|
|
|
for _, n := range options.StaticNodes {
|
2022-08-26 00:18:03 +00:00
|
|
|
go func(ctx context.Context, node multiaddr.Multiaddr) {
|
|
|
|
ctx, cancel := context.WithTimeout(ctx, dialTimeout)
|
|
|
|
defer cancel()
|
2022-08-15 17:13:45 +00:00
|
|
|
err = wakuNode.DialPeerWithMultiAddress(ctx, node)
|
2021-10-03 21:45:07 +00:00
|
|
|
if err != nil {
|
2022-05-27 13:25:06 +00:00
|
|
|
logger.Error("dialing peer", zap.Error(err))
|
2021-03-18 23:21:45 +00:00
|
|
|
}
|
2022-08-26 00:18:03 +00:00
|
|
|
}(ctx, n)
|
2021-10-03 21:45:07 +00:00
|
|
|
}
|
2021-03-18 23:21:45 +00:00
|
|
|
|
2023-07-05 19:17:43 +00:00
|
|
|
if options.DiscV5.Enable {
|
|
|
|
if err = wakuNode.DiscV5().Start(ctx); err != nil {
|
|
|
|
logger.Fatal("starting discovery v5", zap.Error(err))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// retrieve and connect to peer exchange peers
|
|
|
|
if options.PeerExchange.Enable && options.PeerExchange.Node != nil {
|
|
|
|
logger.Info("retrieving peer info via peer exchange protocol")
|
|
|
|
|
2023-09-14 15:00:06 +00:00
|
|
|
peerID, err := wakuNode.AddPeer(*options.PeerExchange.Node, wakupeerstore.Static,
|
|
|
|
pubSubTopicMapKeys, peer_exchange.PeerExchangeID_v20alpha1)
|
2023-07-05 19:17:43 +00:00
|
|
|
if err != nil {
|
|
|
|
logger.Error("adding peer exchange peer", logging.MultiAddrs("node", *options.PeerExchange.Node), zap.Error(err))
|
|
|
|
} else {
|
|
|
|
desiredOutDegree := wakuNode.Relay().Params().D
|
2023-07-06 21:40:57 +00:00
|
|
|
if err = wakuNode.PeerExchange().Request(ctx, desiredOutDegree, peer_exchange.WithPeer(peerID)); err != nil {
|
2023-07-05 19:17:43 +00:00
|
|
|
logger.Error("requesting peers via peer exchange", zap.Error(err))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-24 20:51:42 +00:00
|
|
|
var restServer *rest.WakuRest
|
|
|
|
if options.RESTServer.Enable {
|
2022-12-07 17:34:56 +00:00
|
|
|
wg.Add(1)
|
2023-11-07 14:56:48 +00:00
|
|
|
restConfig := rest.RestConfig{Address: options.RESTServer.Address,
|
|
|
|
Port: uint(options.RESTServer.Port),
|
|
|
|
EnablePProf: options.PProf,
|
|
|
|
EnableAdmin: options.RESTServer.Admin,
|
|
|
|
RelayCacheCapacity: uint(options.RESTServer.RelayCacheCapacity),
|
|
|
|
FilterCacheCapacity: uint(options.RESTServer.FilterCacheCapacity)}
|
|
|
|
|
|
|
|
restServer = rest.NewWakuRest(wakuNode, restConfig, logger)
|
2022-12-10 16:21:22 +00:00
|
|
|
restServer.Start(ctx, &wg)
|
2022-07-24 20:51:42 +00:00
|
|
|
}
|
|
|
|
|
2022-12-07 17:34:56 +00:00
|
|
|
wg.Wait()
|
2022-05-30 18:48:22 +00:00
|
|
|
logger.Info("Node setup complete")
|
2022-05-26 12:23:10 +00:00
|
|
|
|
2021-10-03 21:45:07 +00:00
|
|
|
// Wait for a SIGINT or SIGTERM signal
|
|
|
|
ch := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
<-ch
|
2022-05-27 13:25:06 +00:00
|
|
|
logger.Info("Received signal, shutting down...")
|
2021-04-19 00:03:16 +00:00
|
|
|
|
2021-10-03 21:45:07 +00:00
|
|
|
// shut the node down
|
|
|
|
wakuNode.Stop()
|
2021-06-28 13:20:23 +00:00
|
|
|
|
2022-07-24 20:51:42 +00:00
|
|
|
if options.RESTServer.Enable {
|
2023-10-18 19:21:37 +00:00
|
|
|
if err := restServer.Stop(ctx); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-07-24 20:51:42 +00:00
|
|
|
}
|
|
|
|
|
2021-10-03 21:45:07 +00:00
|
|
|
if options.Metrics.Enable {
|
2023-10-18 19:21:37 +00:00
|
|
|
if err = metricsServer.Stop(ctx); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-10-03 21:45:07 +00:00
|
|
|
}
|
2021-03-18 23:21:45 +00:00
|
|
|
|
2023-10-18 19:21:37 +00:00
|
|
|
if db != nil {
|
|
|
|
if err = db.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-10-03 21:45:07 +00:00
|
|
|
}
|
2023-10-18 19:21:37 +00:00
|
|
|
|
|
|
|
return nil
|
2021-03-18 23:21:45 +00:00
|
|
|
}
|
|
|
|
|
2023-10-20 19:56:18 +00:00
|
|
|
func processTopics(options NodeOptions) (map[string][]string, error) {
|
|
|
|
|
2023-09-06 04:37:21 +00:00
|
|
|
//Using a map to avoid duplicate pub-sub topics that can result from autosharding
|
|
|
|
// or same-topic being passed twice.
|
2023-10-20 19:56:18 +00:00
|
|
|
pubSubTopicMap := make(map[string][]string)
|
2023-09-06 04:37:21 +00:00
|
|
|
|
|
|
|
for _, topic := range options.Relay.Topics.Value() {
|
2023-10-20 19:56:18 +00:00
|
|
|
pubSubTopicMap[topic] = []string{}
|
2023-09-06 04:37:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, topic := range options.Relay.PubSubTopics.Value() {
|
2023-10-20 19:56:18 +00:00
|
|
|
pubSubTopicMap[topic] = []string{}
|
2023-09-06 04:37:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Get pubSub topics from contentTopics if they are as per autosharding
|
|
|
|
for _, cTopic := range options.Relay.ContentTopics.Value() {
|
|
|
|
contentTopic, err := wprotocol.StringToContentTopic(cTopic)
|
|
|
|
if err != nil {
|
2023-10-18 19:21:37 +00:00
|
|
|
return nil, err
|
2023-09-06 04:37:21 +00:00
|
|
|
}
|
|
|
|
pTopic := wprotocol.GetShardFromContentTopic(contentTopic, wprotocol.GenerationZeroShardsCount)
|
2023-10-20 19:56:18 +00:00
|
|
|
if _, ok := pubSubTopicMap[pTopic.String()]; !ok {
|
|
|
|
pubSubTopicMap[pTopic.String()] = []string{}
|
|
|
|
}
|
|
|
|
pubSubTopicMap[pTopic.String()] = append(pubSubTopicMap[pTopic.String()], cTopic)
|
2023-09-06 04:37:21 +00:00
|
|
|
}
|
|
|
|
//If no topics are passed, then use default waku topic.
|
2024-01-02 12:34:43 +00:00
|
|
|
if len(pubSubTopicMap) == 0 && options.ClusterID == 0 {
|
2023-10-20 19:56:18 +00:00
|
|
|
pubSubTopicMap[relay.DefaultWakuTopic] = []string{}
|
2023-09-06 04:37:21 +00:00
|
|
|
}
|
|
|
|
|
2023-10-18 19:21:37 +00:00
|
|
|
return pubSubTopicMap, nil
|
2023-09-06 04:37:21 +00:00
|
|
|
}
|
|
|
|
|
2023-10-18 19:21:37 +00:00
|
|
|
func addStaticPeers(wakuNode *node.WakuNode, addresses []multiaddr.Multiaddr, pubSubTopics []string, protocols ...protocol.ID) error {
|
2022-08-15 17:13:45 +00:00
|
|
|
for _, addr := range addresses {
|
2023-09-14 15:00:06 +00:00
|
|
|
_, err := wakuNode.AddPeer(addr, wakupeerstore.Static, pubSubTopics, protocols...)
|
2023-10-18 19:21:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not add static peer: %w", err)
|
|
|
|
}
|
2021-09-30 16:01:53 +00:00
|
|
|
}
|
2023-10-18 19:21:37 +00:00
|
|
|
return nil
|
2021-09-30 16:01:53 +00:00
|
|
|
}
|
2021-10-04 22:38:27 +00:00
|
|
|
|
2022-07-25 12:24:42 +00:00
|
|
|
func loadPrivateKeyFromFile(path string, passwd string) (*ecdsa.PrivateKey, error) {
|
2023-02-16 16:17:52 +00:00
|
|
|
src, err := os.ReadFile(path)
|
2021-10-04 22:38:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-07-25 12:24:42 +00:00
|
|
|
var encryptedK keystore.CryptoJSON
|
|
|
|
err = json.Unmarshal(src, &encryptedK)
|
2021-10-04 22:38:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-07-25 12:24:42 +00:00
|
|
|
pKey, err := keystore.DecryptDataV3(encryptedK, passwd)
|
2022-05-27 19:55:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-10-04 22:38:27 +00:00
|
|
|
|
2022-07-25 12:24:42 +00:00
|
|
|
return crypto.ToECDSA(pKey)
|
2021-10-04 22:38:27 +00:00
|
|
|
}
|
|
|
|
|
2023-08-09 18:14:54 +00:00
|
|
|
func getPrivKey(options NodeOptions) (*ecdsa.PrivateKey, error) {
|
2021-10-04 22:38:27 +00:00
|
|
|
var prvKey *ecdsa.PrivateKey
|
2023-04-02 10:53:37 +00:00
|
|
|
// get private key from nodeKey or keyFile
|
2022-08-15 17:13:45 +00:00
|
|
|
if options.NodeKey != nil {
|
|
|
|
prvKey = options.NodeKey
|
2021-10-04 22:38:27 +00:00
|
|
|
} else {
|
2023-04-02 10:53:37 +00:00
|
|
|
if _, err := os.Stat(options.KeyFile); err == nil {
|
|
|
|
if prvKey, err = loadPrivateKeyFromFile(options.KeyFile, options.KeyPasswd); err != nil {
|
|
|
|
return nil, fmt.Errorf("could not read keyfile: %w", err)
|
2021-10-04 22:38:27 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-04-02 10:53:37 +00:00
|
|
|
if os.IsNotExist(err) {
|
|
|
|
if prvKey, err = crypto.GenerateKey(); err != nil {
|
|
|
|
return nil, fmt.Errorf("error generating key: %w", err)
|
2021-10-04 22:38:27 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-04-02 10:53:37 +00:00
|
|
|
return nil, fmt.Errorf("could not read keyfile: %w", err)
|
2021-10-04 22:38:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return prvKey, nil
|
|
|
|
}
|
2021-10-14 18:17:01 +00:00
|
|
|
|
2023-08-09 18:14:54 +00:00
|
|
|
func printListeningAddresses(ctx context.Context, nodeOpts []node.WakuNodeOption, options NodeOptions) {
|
2021-10-14 18:17:01 +00:00
|
|
|
params := new(node.WakuNodeParameters)
|
|
|
|
for _, opt := range nodeOpts {
|
|
|
|
err := opt(params)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
2021-10-15 02:15:02 +00:00
|
|
|
|
|
|
|
var libp2pOpts []config.Option
|
2021-11-17 16:19:42 +00:00
|
|
|
libp2pOpts = append(libp2pOpts,
|
|
|
|
params.Identity(),
|
|
|
|
libp2p.ListenAddrs(params.MultiAddresses()...),
|
|
|
|
)
|
2021-10-15 02:15:02 +00:00
|
|
|
|
2022-08-25 20:36:04 +00:00
|
|
|
if options.Websocket.Secure {
|
|
|
|
transports := libp2p.ChainOptions(
|
|
|
|
libp2p.Transport(tcp.NewTCPTransport),
|
|
|
|
libp2p.Transport(ws.New, ws.WithTLSConfig(params.TLSConfig())),
|
|
|
|
)
|
|
|
|
libp2pOpts = append(libp2pOpts, transports)
|
|
|
|
}
|
|
|
|
|
2021-11-17 16:19:42 +00:00
|
|
|
addrFactory := params.AddressFactory()
|
|
|
|
if addrFactory != nil {
|
|
|
|
libp2pOpts = append(libp2pOpts, libp2p.AddrsFactory(addrFactory))
|
2021-10-15 02:15:02 +00:00
|
|
|
}
|
|
|
|
|
2022-03-22 13:12:58 +00:00
|
|
|
h, err := libp2p.New(libp2pOpts...)
|
2021-10-14 18:17:01 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
2023-07-07 15:51:15 +00:00
|
|
|
hostAddrs := utils.EncapsulatePeerID(h.ID(), h.Addrs()...)
|
|
|
|
for _, addr := range hostAddrs {
|
|
|
|
fmt.Println(addr)
|
2021-10-14 18:17:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2024-01-03 01:36:41 +00:00
|
|
|
|
|
|
|
func parseMsgSizeConfig(msgSizeConfig string) int {
|
|
|
|
|
|
|
|
msgSize, err := humanize.ParseBytes(msgSizeConfig)
|
|
|
|
if err != nil {
|
|
|
|
msgSize = 0
|
|
|
|
}
|
|
|
|
return int(msgSize)
|
|
|
|
}
|