2017-03-28 09:04:52 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-01-30 11:51:48 +00:00
|
|
|
"context"
|
2018-05-08 21:57:29 +00:00
|
|
|
"errors"
|
2017-11-03 22:07:13 +00:00
|
|
|
"flag"
|
2017-03-28 09:04:52 +00:00
|
|
|
"fmt"
|
2018-03-23 13:26:28 +00:00
|
|
|
stdlog "log"
|
2017-03-28 09:04:52 +00:00
|
|
|
"os"
|
2018-01-23 05:16:13 +00:00
|
|
|
"os/signal"
|
2018-09-21 14:09:31 +00:00
|
|
|
"path/filepath"
|
2017-03-28 09:04:52 +00:00
|
|
|
"runtime"
|
2017-11-03 22:07:13 +00:00
|
|
|
"strings"
|
2018-06-25 15:21:04 +00:00
|
|
|
"time"
|
2017-03-28 09:04:52 +00:00
|
|
|
|
2020-08-20 07:26:00 +00:00
|
|
|
"github.com/google/uuid"
|
2020-01-02 09:10:19 +00:00
|
|
|
"github.com/okzk/sdnotify"
|
|
|
|
"golang.org/x/crypto/ssh/terminal"
|
|
|
|
|
2018-03-20 18:35:28 +00:00
|
|
|
"github.com/ethereum/go-ethereum/log"
|
2018-06-25 15:21:04 +00:00
|
|
|
gethmetrics "github.com/ethereum/go-ethereum/metrics"
|
2020-01-02 09:10:19 +00:00
|
|
|
|
2018-06-08 11:29:50 +00:00
|
|
|
"github.com/status-im/status-go/api"
|
2020-08-20 07:26:00 +00:00
|
|
|
"github.com/status-im/status-go/appdatabase"
|
|
|
|
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
|
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
2018-09-13 16:31:29 +00:00
|
|
|
"github.com/status-im/status-go/logutils"
|
2019-10-09 15:04:16 +00:00
|
|
|
"github.com/status-im/status-go/metrics"
|
2018-01-30 11:51:48 +00:00
|
|
|
nodemetrics "github.com/status-im/status-go/metrics/node"
|
2018-06-08 11:29:50 +00:00
|
|
|
"github.com/status-im/status-go/node"
|
|
|
|
"github.com/status-im/status-go/params"
|
2018-03-23 13:58:40 +00:00
|
|
|
"github.com/status-im/status-go/profiling"
|
2020-08-20 07:26:00 +00:00
|
|
|
"github.com/status-im/status-go/protocol"
|
2022-09-27 20:27:20 +00:00
|
|
|
"github.com/status-im/status-go/sqlite"
|
2023-08-11 11:28:45 +00:00
|
|
|
"github.com/status-im/status-go/walletdatabase"
|
2017-03-28 09:04:52 +00:00
|
|
|
)
|
|
|
|
|
2018-06-08 09:20:30 +00:00
|
|
|
const (
|
|
|
|
serverClientName = "Statusd"
|
|
|
|
)
|
|
|
|
|
2017-03-28 09:04:52 +00:00
|
|
|
var (
|
2022-03-08 13:17:26 +00:00
|
|
|
configFiles configFlags
|
|
|
|
logLevel = flag.String("log", "", `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE"`)
|
|
|
|
logWithoutColors = flag.Bool("log-without-color", false, "Disables log colors")
|
|
|
|
ipcEnabled = flag.Bool("ipc", false, "Enable IPC RPC endpoint")
|
|
|
|
ipcFile = flag.String("ipcfile", "", "Set IPC file path")
|
|
|
|
pprofEnabled = flag.Bool("pprof", false, "Enable runtime profiling via pprof")
|
|
|
|
pprofPort = flag.Int("pprof-port", 52525, "Port for runtime profiling via pprof")
|
|
|
|
communityArchiveSupportEnabled = flag.Bool("community-archives", false, "Enable community history archive support")
|
|
|
|
torrentClientPort = flag.Int("torrent-client-port", 9025, "Port for BitTorrent protocol connections")
|
|
|
|
version = flag.Bool("version", false, "Print version and dump configuration")
|
2018-01-17 20:07:45 +00:00
|
|
|
|
2018-09-21 14:09:31 +00:00
|
|
|
dataDir = flag.String("dir", getDefaultDataDir(), "Directory used by node to store data")
|
|
|
|
register = flag.Bool("register", false, "Register and make the node discoverable by other nodes")
|
|
|
|
mailserver = flag.Bool("mailserver", false, "Enable Mail Server with default configuration")
|
2018-09-26 06:49:31 +00:00
|
|
|
networkID = flag.Int(
|
|
|
|
"network-id",
|
2022-10-20 10:33:23 +00:00
|
|
|
params.GoerliNetworkID,
|
2018-09-26 06:49:31 +00:00
|
|
|
fmt.Sprintf(
|
2022-10-20 10:33:23 +00:00
|
|
|
"A network ID: %d (Mainnet), %d (Goerli)",
|
|
|
|
params.MainNetworkID, params.GoerliNetworkID,
|
2018-09-26 06:49:31 +00:00
|
|
|
),
|
|
|
|
)
|
2020-02-26 19:36:25 +00:00
|
|
|
fleet = flag.String(
|
|
|
|
"fleet",
|
|
|
|
params.FleetProd,
|
|
|
|
fmt.Sprintf(
|
|
|
|
"Select fleet: %s (default %s)",
|
2022-03-11 20:48:51 +00:00
|
|
|
[]string{params.FleetProd, params.FleetStaging, params.FleetTest, params.FleetWakuV2Prod, params.FleetWakuV2Test, params.FleetStatusTest, params.FleetStatusProd}, params.FleetProd,
|
2020-02-26 19:36:25 +00:00
|
|
|
),
|
|
|
|
)
|
2020-03-10 12:40:35 +00:00
|
|
|
listenAddr = flag.String("addr", "", "address to bind listener to")
|
2018-09-21 14:09:31 +00:00
|
|
|
|
2018-02-05 19:25:40 +00:00
|
|
|
// don't change the name of this flag, https://github.com/ethereum/go-ethereum/blob/master/metrics/metrics.go#L41
|
2019-10-09 15:04:16 +00:00
|
|
|
metricsEnabled = flag.Bool("metrics", false, "Expose ethereum metrics with debug_metrics jsonrpc call")
|
|
|
|
metricsPort = flag.Int("metrics-port", 9305, "Port for the Prometheus /metrics endpoint")
|
2017-11-03 22:07:13 +00:00
|
|
|
)
|
2017-05-03 14:24:48 +00:00
|
|
|
|
2018-03-20 18:35:28 +00:00
|
|
|
// All general log messages in this package should be routed through this logger.
|
|
|
|
var logger = log.New("package", "status-go/cmd/statusd")
|
|
|
|
|
2018-07-25 14:03:35 +00:00
|
|
|
func init() {
|
2018-09-13 16:31:29 +00:00
|
|
|
flag.Var(&configFiles, "c", "JSON configuration file(s). Multiple configuration files can be specified, and will be merged in occurrence order")
|
2019-10-04 15:21:24 +00:00
|
|
|
}
|
2018-09-13 16:31:29 +00:00
|
|
|
|
2019-10-04 15:21:24 +00:00
|
|
|
// nolint:gocyclo
|
|
|
|
func main() {
|
2018-09-13 16:31:29 +00:00
|
|
|
colors := terminal.IsTerminal(int(os.Stdin.Fd()))
|
2019-03-01 13:37:13 +00:00
|
|
|
if err := logutils.OverrideRootLog(true, "ERROR", logutils.FileOptions{}, colors); err != nil {
|
2018-09-13 16:31:29 +00:00
|
|
|
stdlog.Fatalf("Error initializing logger: %v", err)
|
|
|
|
}
|
2018-04-10 06:44:09 +00:00
|
|
|
|
2017-11-03 22:07:13 +00:00
|
|
|
flag.Usage = printUsage
|
|
|
|
flag.Parse()
|
2018-05-17 13:03:23 +00:00
|
|
|
if flag.NArg() > 0 {
|
|
|
|
printUsage()
|
2018-09-13 16:31:29 +00:00
|
|
|
logger.Error("Extra args in command line: %v", flag.Args())
|
2018-05-17 13:03:23 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
2018-07-25 14:03:35 +00:00
|
|
|
|
2020-02-26 19:36:25 +00:00
|
|
|
opts := []params.Option{params.WithFleet(*fleet)}
|
2018-09-21 14:09:31 +00:00
|
|
|
if *mailserver {
|
|
|
|
opts = append(opts, params.WithMailserver())
|
|
|
|
}
|
|
|
|
|
2018-09-19 18:29:42 +00:00
|
|
|
config, err := params.NewNodeConfigWithDefaultsAndFiles(
|
2018-09-21 14:09:31 +00:00
|
|
|
*dataDir,
|
2018-09-26 06:49:31 +00:00
|
|
|
uint64(*networkID),
|
2018-09-21 14:09:31 +00:00
|
|
|
opts,
|
|
|
|
configFiles,
|
2018-09-19 18:29:42 +00:00
|
|
|
)
|
2017-11-03 22:07:13 +00:00
|
|
|
if err != nil {
|
2018-09-13 16:31:29 +00:00
|
|
|
printUsage()
|
2019-06-12 09:16:00 +00:00
|
|
|
logger.Error(err.Error())
|
2018-09-13 16:31:29 +00:00
|
|
|
os.Exit(1)
|
2017-05-16 03:24:56 +00:00
|
|
|
}
|
2018-09-13 16:31:29 +00:00
|
|
|
|
2020-03-10 12:40:35 +00:00
|
|
|
// Use listenAddr if and only if explicitly provided in the arguments.
|
|
|
|
// The default value is set in params.NewNodeConfigWithDefaultsAndFiles().
|
|
|
|
if *listenAddr != "" {
|
|
|
|
config.ListenAddr = *listenAddr
|
|
|
|
}
|
2020-02-26 19:36:25 +00:00
|
|
|
|
2018-09-21 14:09:31 +00:00
|
|
|
if *register && *mailserver {
|
|
|
|
config.RegisterTopics = append(config.RegisterTopics, params.MailServerDiscv5Topic)
|
|
|
|
} else if *register {
|
|
|
|
config.RegisterTopics = append(config.RegisterTopics, params.WhisperDiscv5Topic)
|
2018-09-19 18:29:42 +00:00
|
|
|
}
|
|
|
|
|
2018-10-11 10:29:59 +00:00
|
|
|
// enable IPC RPC
|
|
|
|
if *ipcEnabled {
|
|
|
|
config.IPCEnabled = true
|
|
|
|
config.IPCFile = *ipcFile
|
|
|
|
}
|
|
|
|
|
2022-03-08 13:17:26 +00:00
|
|
|
if *communityArchiveSupportEnabled {
|
|
|
|
config.TorrentConfig.Enabled = true
|
|
|
|
config.TorrentConfig.Port = *torrentClientPort
|
|
|
|
}
|
|
|
|
|
2018-09-21 14:09:31 +00:00
|
|
|
// set up logging options
|
|
|
|
setupLogging(config)
|
2018-09-13 16:31:29 +00:00
|
|
|
|
2018-06-08 09:20:30 +00:00
|
|
|
// We want statusd to be distinct from StatusIM client.
|
|
|
|
config.Name = serverClientName
|
2017-05-16 03:24:56 +00:00
|
|
|
|
2017-11-03 22:07:13 +00:00
|
|
|
if *version {
|
2020-03-10 12:40:35 +00:00
|
|
|
printVersion(config)
|
2017-11-03 22:07:13 +00:00
|
|
|
return
|
2017-03-28 09:04:52 +00:00
|
|
|
}
|
2017-05-03 14:24:48 +00:00
|
|
|
|
2019-11-23 17:57:05 +00:00
|
|
|
backend := api.NewGethStatusBackend()
|
2019-08-31 14:55:05 +00:00
|
|
|
err = backend.AccountManager().InitKeystore(config.KeyStoreDir)
|
|
|
|
if err != nil {
|
|
|
|
logger.Error("Failed to init keystore", "error", err)
|
|
|
|
return
|
|
|
|
}
|
2018-02-09 13:37:56 +00:00
|
|
|
err = backend.StartNode(config)
|
2017-11-03 22:07:13 +00:00
|
|
|
if err != nil {
|
2018-03-20 18:35:28 +00:00
|
|
|
logger.Error("Node start failed", "error", err)
|
2017-11-03 22:07:13 +00:00
|
|
|
return
|
2017-03-28 09:04:52 +00:00
|
|
|
}
|
2017-05-03 14:24:48 +00:00
|
|
|
|
2020-08-20 09:05:39 +00:00
|
|
|
err = sdnotify.Ready()
|
|
|
|
if err == sdnotify.ErrSdNotifyNoSocket {
|
|
|
|
logger.Debug("sd_notify socket not available")
|
|
|
|
} else if err != nil {
|
|
|
|
logger.Warn("sd_notify READY call failed", "error", err)
|
|
|
|
} else {
|
|
|
|
// systemd aliveness notifications, affects only Linux
|
|
|
|
go startSystemDWatchdog()
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle interrupt signals
|
|
|
|
interruptCh := haltOnInterruptSignal(backend.StatusNode())
|
|
|
|
|
|
|
|
// Start collecting metrics. Metrics can be enabled by providing `-metrics` flag
|
|
|
|
// or setting `gethmetrics.Enabled` to true during compilation time:
|
|
|
|
// https://github.com/status-im/go-ethereum/pull/76.
|
|
|
|
if *metricsEnabled || gethmetrics.Enabled {
|
|
|
|
go startCollectingNodeMetrics(interruptCh, backend.StatusNode())
|
|
|
|
go gethmetrics.CollectProcessMetrics(3 * time.Second)
|
|
|
|
go metrics.NewMetricsServer(*metricsPort, gethmetrics.DefaultRegistry).Listen()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if profiling shall be enabled.
|
|
|
|
if *pprofEnabled {
|
|
|
|
profiling.NewProfiler(*pprofPort).Go()
|
|
|
|
}
|
|
|
|
|
2020-08-20 07:26:00 +00:00
|
|
|
if config.PushNotificationServerConfig.Enabled {
|
|
|
|
if config.NodeKey == "" {
|
|
|
|
logger.Error("node key needs to be set if running a push notification server")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
identity, err := crypto.HexToECDSA(config.NodeKey)
|
|
|
|
if err != nil {
|
|
|
|
logger.Error("node key is invalid", "error", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate installationID from public key, so it's always the same
|
|
|
|
installationID, err := uuid.FromBytes(crypto.CompressPubkey(&identity.PublicKey)[:16])
|
|
|
|
if err != nil {
|
|
|
|
logger.Error("cannot create installation id", "error", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-08-11 11:28:45 +00:00
|
|
|
walletDB, err := walletdatabase.InitializeDB(config.DataDir+"/"+installationID.String()+"-wallet.db", "", sqlite.ReducedKDFIterationsNumber)
|
|
|
|
if err != nil {
|
|
|
|
logger.Error("failed to initialize app db", "error", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
appDB, err := appdatabase.InitializeDB(config.DataDir+"/"+installationID.String()+".db", "", sqlite.ReducedKDFIterationsNumber)
|
2020-08-20 07:26:00 +00:00
|
|
|
if err != nil {
|
|
|
|
logger.Error("failed to initialize app db", "error", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
options := []protocol.Option{
|
|
|
|
protocol.WithPushNotifications(),
|
|
|
|
protocol.WithPushNotificationServerConfig(&config.PushNotificationServerConfig),
|
2023-08-11 11:28:45 +00:00
|
|
|
protocol.WithDatabase(appDB),
|
|
|
|
protocol.WithWalletDatabase(walletDB),
|
2022-03-08 13:17:26 +00:00
|
|
|
protocol.WithTorrentConfig(&config.TorrentConfig),
|
2023-03-27 09:35:03 +00:00
|
|
|
protocol.WithWalletConfig(&config.WalletConfig),
|
Check token funds when handling community requests to join
This adds checks to `HandleCommunityRequestToJoin` and
`AcceptRequestToJoinCommunity` that ensure a given user's revealed
wallet addresses own the token funds required by a community.
When community has token permissions of type `BECOME_MEMBER`, the
following happens when the owner receives a request:
1. Upon verifying provided wallet addresses by the requester, the owner
node accumulates all token funds related to the given wallets that
match the token criteria in the configured permissions
2. If the requester does not meet the necessary requirements, the
request to join will be declined. If the requester does have the
funds, he'll either be automatically accepted to the community, or
enters the next stage where an owner needs to manually accept the
request.
3. The the community does not automatically accept users, then the funds
check will happen again, when the owner tries to manually accept the
request. If the necessary funds do not exist at this stage, the
request will be declined
4. Upon accepting, whether automatically or manually, the owner adds the
requester's wallet addresses to the `CommunityDescription`, such that
they can be retrieved later when doing periodic checks or when
permissions have changed.
2023-03-16 14:35:33 +00:00
|
|
|
protocol.WithRPCClient(backend.StatusNode().RPCClient()),
|
2020-08-20 07:26:00 +00:00
|
|
|
}
|
|
|
|
|
2021-11-03 12:38:37 +00:00
|
|
|
messenger, err := protocol.NewMessenger(
|
|
|
|
config.Name,
|
|
|
|
identity,
|
|
|
|
gethbridge.NewNodeBridge(backend.StatusNode().GethNode(), backend.StatusNode().WakuService(), backend.StatusNode().WakuV2Service()),
|
|
|
|
installationID.String(),
|
2022-01-12 16:02:01 +00:00
|
|
|
nil,
|
2023-03-10 12:53:40 +00:00
|
|
|
backend.AccountManager(),
|
2021-11-03 12:38:37 +00:00
|
|
|
options...,
|
|
|
|
)
|
2020-08-20 07:26:00 +00:00
|
|
|
if err != nil {
|
|
|
|
logger.Error("failed to create messenger", "error", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-08-20 09:05:39 +00:00
|
|
|
err = messenger.Init()
|
|
|
|
if err != nil {
|
|
|
|
logger.Error("failed to init messenger", "error", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-08-20 07:26:00 +00:00
|
|
|
// This will start the push notification server as well as
|
|
|
|
// the config is set to Enabled
|
2021-01-14 22:15:13 +00:00
|
|
|
_, err = messenger.Start()
|
2020-08-20 07:26:00 +00:00
|
|
|
if err != nil {
|
|
|
|
logger.Error("failed to start messenger", "error", err)
|
|
|
|
return
|
|
|
|
}
|
2020-08-20 09:05:39 +00:00
|
|
|
go retrieveMessagesLoop(messenger, 300*time.Millisecond, interruptCh)
|
2018-02-07 10:48:03 +00:00
|
|
|
}
|
|
|
|
|
2018-06-12 16:50:25 +00:00
|
|
|
gethNode := backend.StatusNode().GethNode()
|
|
|
|
if gethNode != nil {
|
2018-04-16 12:36:09 +00:00
|
|
|
// wait till node has been stopped
|
2018-06-12 16:50:25 +00:00
|
|
|
gethNode.Wait()
|
2019-09-16 09:38:33 +00:00
|
|
|
if err := sdnotify.Stopping(); err != nil {
|
|
|
|
logger.Warn("sd_notify STOPPING call failed", "error", err)
|
|
|
|
}
|
2017-03-28 09:04:52 +00:00
|
|
|
}
|
2017-11-03 22:07:13 +00:00
|
|
|
}
|
2017-05-03 14:24:48 +00:00
|
|
|
|
2018-09-21 14:09:31 +00:00
|
|
|
func getDefaultDataDir() string {
|
|
|
|
if home := os.Getenv("HOME"); home != "" {
|
|
|
|
return filepath.Join(home, ".statusd")
|
|
|
|
}
|
|
|
|
return "./statusd-data"
|
|
|
|
}
|
|
|
|
|
|
|
|
func setupLogging(config *params.NodeConfig) {
|
|
|
|
if *logLevel != "" {
|
|
|
|
config.LogLevel = *logLevel
|
|
|
|
}
|
|
|
|
|
2021-08-18 12:44:10 +00:00
|
|
|
logSettings := logutils.LogSettings{
|
|
|
|
Enabled: config.LogEnabled,
|
|
|
|
MobileSystem: config.LogMobileSystem,
|
|
|
|
Level: config.LogLevel,
|
|
|
|
File: config.LogFile,
|
|
|
|
MaxSize: config.LogMaxSize,
|
|
|
|
MaxBackups: config.LogMaxBackups,
|
|
|
|
CompressRotated: config.LogCompressRotated,
|
|
|
|
}
|
2018-09-21 14:09:31 +00:00
|
|
|
colors := !(*logWithoutColors) && terminal.IsTerminal(int(os.Stdin.Fd()))
|
2021-08-18 12:44:10 +00:00
|
|
|
if err := logutils.OverrideRootLogWithConfig(logSettings, colors); err != nil {
|
2018-09-21 14:09:31 +00:00
|
|
|
stdlog.Fatalf("Error initializing logger: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-16 09:38:33 +00:00
|
|
|
// loop for notifying systemd about process being alive
|
|
|
|
func startSystemDWatchdog() {
|
|
|
|
for range time.Tick(30 * time.Second) {
|
|
|
|
if err := sdnotify.Watchdog(); err != nil {
|
|
|
|
logger.Warn("sd_notify WATCHDOG call failed", "error", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-30 11:51:48 +00:00
|
|
|
// startCollectingStats collects various stats about the node and other protocols like Whisper.
|
2018-05-16 15:36:59 +00:00
|
|
|
func startCollectingNodeMetrics(interruptCh <-chan struct{}, statusNode *node.StatusNode) {
|
|
|
|
logger.Info("Starting collecting node metrics")
|
2018-01-30 11:51:48 +00:00
|
|
|
|
2018-06-12 16:50:25 +00:00
|
|
|
gethNode := statusNode.GethNode()
|
|
|
|
if gethNode == nil {
|
2018-04-16 12:36:09 +00:00
|
|
|
logger.Error("Failed to run metrics because it could not get the node")
|
2018-01-30 11:51:48 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
go func() {
|
2018-11-12 09:27:09 +00:00
|
|
|
// Try to subscribe and collect metrics. In case of an error, retry.
|
|
|
|
for {
|
|
|
|
if err := nodemetrics.SubscribeServerEvents(ctx, gethNode); err != nil {
|
|
|
|
logger.Error("Failed to subscribe server events", "error", err)
|
|
|
|
} else {
|
|
|
|
// no error means that the subscription was terminated by purpose
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(time.Second)
|
2018-01-30 11:51:48 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
<-interruptCh
|
|
|
|
}
|
|
|
|
|
2018-09-13 16:31:29 +00:00
|
|
|
var (
|
|
|
|
errStatusServiceRequiresIPC = errors.New("to enable the StatusService on IPC, -ipc flag must be set")
|
|
|
|
errStatusServiceRequiresHTTP = errors.New("to enable the StatusService on HTTP, -http flag must be set")
|
|
|
|
errStatusServiceInvalidFlag = errors.New("-status flag valid values are: ipc, http")
|
|
|
|
)
|
2018-05-08 21:57:29 +00:00
|
|
|
|
|
|
|
func configureStatusService(flagValue string, nodeConfig *params.NodeConfig) (*params.NodeConfig, error) {
|
|
|
|
switch flagValue {
|
|
|
|
case "ipc":
|
|
|
|
if !nodeConfig.IPCEnabled {
|
|
|
|
return nil, errStatusServiceRequiresIPC
|
|
|
|
}
|
2019-01-17 12:56:22 +00:00
|
|
|
nodeConfig.EnableStatusService = true
|
2018-05-08 21:57:29 +00:00
|
|
|
case "http":
|
2018-09-21 14:09:31 +00:00
|
|
|
if !nodeConfig.HTTPEnabled {
|
2018-05-08 21:57:29 +00:00
|
|
|
return nil, errStatusServiceRequiresHTTP
|
|
|
|
}
|
2019-01-17 12:56:22 +00:00
|
|
|
nodeConfig.EnableStatusService = true
|
2018-05-08 21:57:29 +00:00
|
|
|
nodeConfig.AddAPIModule("status")
|
|
|
|
case "":
|
2019-01-17 12:56:22 +00:00
|
|
|
nodeConfig.EnableStatusService = false
|
2018-05-08 21:57:29 +00:00
|
|
|
default:
|
|
|
|
return nil, errStatusServiceInvalidFlag
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeConfig, nil
|
|
|
|
}
|
|
|
|
|
2017-11-03 22:07:13 +00:00
|
|
|
// printVersion prints verbose output about version and config.
|
2020-03-10 12:40:35 +00:00
|
|
|
func printVersion(config *params.NodeConfig) {
|
2018-06-08 09:20:30 +00:00
|
|
|
fmt.Println(strings.Title(config.Name))
|
|
|
|
fmt.Println("Version:", config.Version)
|
2020-02-10 11:22:37 +00:00
|
|
|
fmt.Println("Network ID:", config.NetworkID)
|
2017-11-03 22:07:13 +00:00
|
|
|
fmt.Println("Go Version:", runtime.Version())
|
|
|
|
fmt.Println("OS:", runtime.GOOS)
|
|
|
|
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
|
|
|
|
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
|
|
|
|
|
|
|
|
fmt.Println("Loaded Config: ", config)
|
2017-03-28 09:04:52 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 22:07:13 +00:00
|
|
|
func printUsage() {
|
2018-01-17 16:46:21 +00:00
|
|
|
usage := `
|
|
|
|
Usage: statusd [options]
|
2017-11-03 22:07:13 +00:00
|
|
|
Examples:
|
2018-09-21 14:09:31 +00:00
|
|
|
statusd # run regular Whisper node that joins Status network
|
2018-09-13 16:31:29 +00:00
|
|
|
statusd -c ./default.json # run node with configuration specified in ./default.json file
|
|
|
|
statusd -c ./default.json -c ./standalone.json # run node with configuration specified in ./default.json file, after merging ./standalone.json file
|
|
|
|
statusd -c ./default.json -metrics # run node with configuration specified in ./default.json file, and expose ethereum metrics with debug_metrics jsonrpc call
|
2017-11-03 22:07:13 +00:00
|
|
|
|
|
|
|
Options:
|
2018-01-17 16:46:21 +00:00
|
|
|
`
|
2019-10-04 15:21:24 +00:00
|
|
|
fmt.Fprint(os.Stderr, usage)
|
2017-11-03 22:07:13 +00:00
|
|
|
flag.PrintDefaults()
|
2017-03-28 09:04:52 +00:00
|
|
|
}
|
2018-01-23 05:16:13 +00:00
|
|
|
|
|
|
|
// haltOnInterruptSignal catches interrupt signal (SIGINT) and
|
|
|
|
// stops the node. It times out after 5 seconds
|
|
|
|
// if the node can not be stopped.
|
2018-04-05 09:45:26 +00:00
|
|
|
func haltOnInterruptSignal(statusNode *node.StatusNode) <-chan struct{} {
|
2018-01-30 11:51:48 +00:00
|
|
|
interruptCh := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
signalCh := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(signalCh, os.Interrupt)
|
|
|
|
defer signal.Stop(signalCh)
|
|
|
|
<-signalCh
|
|
|
|
close(interruptCh)
|
2018-03-20 18:35:28 +00:00
|
|
|
logger.Info("Got interrupt, shutting down...")
|
2018-04-05 09:45:26 +00:00
|
|
|
if err := statusNode.Stop(); err != nil {
|
2018-03-20 18:35:28 +00:00
|
|
|
logger.Error("Failed to stop node", "error", err)
|
2018-01-30 11:51:48 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return interruptCh
|
2018-01-23 05:16:13 +00:00
|
|
|
}
|
2020-08-20 09:05:39 +00:00
|
|
|
|
|
|
|
// retrieveMessagesLoop fetches messages from a messenger so that they are processed
|
|
|
|
func retrieveMessagesLoop(messenger *protocol.Messenger, tick time.Duration, cancel <-chan struct{}) {
|
|
|
|
ticker := time.NewTicker(tick)
|
|
|
|
defer ticker.Stop()
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ticker.C:
|
2021-03-31 16:23:45 +00:00
|
|
|
_, err := messenger.RetrieveAll()
|
2020-08-20 09:05:39 +00:00
|
|
|
if err != nil {
|
|
|
|
logger.Error("failed to retrieve raw messages", "err", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
case <-cancel:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|