2017-03-28 09:04:52 +00:00
package main
import (
2018-01-30 11:51:48 +00:00
"context"
2024-05-13 13:02:22 +00:00
"database/sql"
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"
2024-10-04 13:24:36 +00:00
"github.com/status-im/status-go/cmd/status-backend/server"
2023-10-02 09:28:42 +00:00
"github.com/status-im/status-go/common/dbsetup"
2020-08-20 07:26:00 +00:00
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"
2023-10-02 09:28:42 +00:00
"github.com/status-im/status-go/protocol/pushnotificationserver"
2024-06-02 18:28:55 +00:00
"github.com/status-im/status-go/protocol/requests"
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" ,
2024-10-15 07:29:21 +00:00
params . SepoliaNetworkID ,
2018-09-26 06:49:31 +00:00
fmt . Sprintf (
2024-10-15 07:29:21 +00:00
"A network ID: %d (Mainnet), %d (Sepolia)" ,
params . MainNetworkID , params . SepoliaNetworkID ,
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)" ,
2024-05-16 00:09:28 +00:00
[ ] string {
params . FleetProd ,
2024-07-11 14:37:16 +00:00
params . FleetStatusStaging ,
2024-03-15 15:30:16 +00:00
params . FleetStatusProd ,
2024-05-17 15:22:45 +00:00
params . FleetWakuSandbox ,
params . FleetWakuTest ,
2024-03-15 15:30:16 +00:00
} ,
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" )
2024-09-12 13:35:25 +00:00
serverAddr = flag . String ( "server" , "" , "Address `host:port` for HTTP API server of statusd" )
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" )
2024-06-02 18:28:55 +00:00
seedPhrase = flag . String ( "seed-phrase" , "" , "Seed phrase for account creation" )
password = flag . String ( "password" , "" , "Password for account" )
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
2024-06-02 18:28:55 +00:00
if * seedPhrase != "" && * password == "" {
printUsage ( )
logger . Error ( "password is required when seed phrase is provided" )
os . Exit ( 1 )
}
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
2024-09-12 13:35:25 +00:00
if serverAddr != nil && * serverAddr != "" {
srv := server . NewServer ( )
srv . Setup ( )
err = srv . Listen ( * serverAddr )
if err != nil {
logger . Error ( "failed to start server" , "error" , err )
return
}
2024-09-27 15:02:18 +00:00
go srv . Serve ( )
2024-09-12 13:35:25 +00:00
log . Info ( "server started" , "address" , srv . Address ( ) )
defer func ( ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 5 * time . Second )
defer cancel ( )
srv . Stop ( ctx )
} ( )
}
test_: Code Migration from status-cli-tests
author shashankshampi <shashank.sanket1995@gmail.com> 1729780155 +0530
committer shashankshampi <shashank.sanket1995@gmail.com> 1730274350 +0530
test: Code Migration from status-cli-tests
fix_: functional tests (#5979)
* fix_: generate on test-functional
* chore(test)_: fix functional test assertion
---------
Co-authored-by: Siddarth Kumar <siddarthkay@gmail.com>
feat(accounts)_: cherry-pick Persist acceptance of Terms of Use & Privacy policy (#5766) (#5977)
* feat(accounts)_: Persist acceptance of Terms of Use & Privacy policy (#5766)
The original GH issue https://github.com/status-im/status-mobile/issues/21113
came from a request from the Legal team. We must show to Status v1 users the new
terms (Terms of Use & Privacy Policy) right after they upgrade to Status v2
from the stores.
The solution we use is to create a flag in the accounts table, named
hasAcceptedTerms. The flag will be set to true on the first account ever
created in v2 and we provide a native call in mobile/status.go#AcceptTerms,
which allows the client to persist the user's choice in case they are upgrading
(from v1 -> v2, or from a v2 older than this PR).
This solution is not the best because we should store the setting in a separate
table, not in the accounts table.
Related Mobile PR https://github.com/status-im/status-mobile/pull/21124
* fix(test)_: Compare addresses using uppercased strings
---------
Co-authored-by: Icaro Motta <icaro.ldm@gmail.com>
test_: restore account (#5960)
feat_: `LogOnPanic` linter (#5969)
* feat_: LogOnPanic linter
* fix_: add missing defer LogOnPanic
* chore_: make vendor
* fix_: tests, address pr comments
* fix_: address pr comments
fix(ci)_: remove workspace and tmp dir
This ensures we do not encounter weird errors like:
```
+ ln -s /home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907 /home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907@tmp/go/src/github.com/status-im/status-go
ln: failed to create symbolic link '/home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907@tmp/go/src/github.com/status-im/status-go': File exists
script returned exit code 1
```
Signed-off-by: Jakub Sokołowski <jakub@status.im>
chore_: enable windows and macos CI build (#5840)
- Added support for Windows and macOS in CI pipelines
- Added missing dependencies for Windows and x86-64-darwin
- Resolved macOS SDK version compatibility for darwin-x86_64
The `mkShell` override was necessary to ensure compatibility with the newer
macOS SDK (version 11.0) for x86_64. The default SDK (10.12) was causing build failures
because of the missing libs and frameworks. OverrideSDK creates a mapping from
the default SDK in all package categories to the requested SDK (11.0).
fix(contacts)_: fix trust status not being saved to cache when changed (#5965)
Fixes https://github.com/status-im/status-desktop/issues/16392
cleanup
added logger and cleanup
review comments changes
fix_: functional tests (#5979)
* fix_: generate on test-functional
* chore(test)_: fix functional test assertion
---------
Co-authored-by: Siddarth Kumar <siddarthkay@gmail.com>
feat(accounts)_: cherry-pick Persist acceptance of Terms of Use & Privacy policy (#5766) (#5977)
* feat(accounts)_: Persist acceptance of Terms of Use & Privacy policy (#5766)
The original GH issue https://github.com/status-im/status-mobile/issues/21113
came from a request from the Legal team. We must show to Status v1 users the new
terms (Terms of Use & Privacy Policy) right after they upgrade to Status v2
from the stores.
The solution we use is to create a flag in the accounts table, named
hasAcceptedTerms. The flag will be set to true on the first account ever
created in v2 and we provide a native call in mobile/status.go#AcceptTerms,
which allows the client to persist the user's choice in case they are upgrading
(from v1 -> v2, or from a v2 older than this PR).
This solution is not the best because we should store the setting in a separate
table, not in the accounts table.
Related Mobile PR https://github.com/status-im/status-mobile/pull/21124
* fix(test)_: Compare addresses using uppercased strings
---------
Co-authored-by: Icaro Motta <icaro.ldm@gmail.com>
test_: restore account (#5960)
feat_: `LogOnPanic` linter (#5969)
* feat_: LogOnPanic linter
* fix_: add missing defer LogOnPanic
* chore_: make vendor
* fix_: tests, address pr comments
* fix_: address pr comments
chore_: enable windows and macos CI build (#5840)
- Added support for Windows and macOS in CI pipelines
- Added missing dependencies for Windows and x86-64-darwin
- Resolved macOS SDK version compatibility for darwin-x86_64
The `mkShell` override was necessary to ensure compatibility with the newer
macOS SDK (version 11.0) for x86_64. The default SDK (10.12) was causing build failures
because of the missing libs and frameworks. OverrideSDK creates a mapping from
the default SDK in all package categories to the requested SDK (11.0).
fix(contacts)_: fix trust status not being saved to cache when changed (#5965)
Fixes https://github.com/status-im/status-desktop/issues/16392
test_: remove port bind
chore(wallet)_: move route execution code to separate module
chore_: replace geth logger with zap logger (#5962)
closes: #6002
feat(telemetry)_: add metrics for message reliability (#5899)
* feat(telemetry)_: track message reliability
Add metrics for dial errors, missed messages,
missed relevant messages, and confirmed delivery.
* fix_: handle error from json marshal
chore_: use zap logger as request logger
iterates: status-im/status-desktop#16536
test_: unique project per run
test_: use docker compose v2, more concrete project name
fix(codecov)_: ignore folders without tests
Otherwise Codecov reports incorrect numbers when making changes.
https://docs.codecov.com/docs/ignoring-paths
Signed-off-by: Jakub Sokołowski <jakub@status.im>
test_: verify schema of signals during init; fix schema verification warnings (#5947)
fix_: update defaultGorushURL (#6011)
fix(tests)_: use non-standard port to avoid conflicts
We have observed `nimbus-eth2` build failures reporting this port:
```json
{
"lvl": "NTC",
"ts": "2024-10-28 13:51:32.308+00:00",
"msg": "REST HTTP server could not be started",
"topics": "beacnde",
"address": "127.0.0.1:5432",
"reason": "(98) Address already in use"
}
```
https://ci.status.im/job/nimbus-eth2/job/platforms/job/linux/job/x86_64/job/main/job/PR-6683/3/
Signed-off-by: Jakub Sokołowski <jakub@status.im>
fix_: create request logger ad-hoc in tests
Fixes `TestCall` failing when run concurrently.
chore_: configure codecov (#6005)
* chore_: configure codecov
* fix_: after_n_builds
2024-10-24 14:29:15 +00:00
backend := api . NewGethStatusBackend ( logutils . ZapLogger ( ) )
2024-05-13 13:02:22 +00:00
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
}
2024-06-02 18:28:55 +00:00
if * seedPhrase != "" {
// Remove data inside dir to avoid conflicts with existing data or account restoration fails
if err := os . RemoveAll ( config . DataDir ) ; err != nil {
logger . Error ( "failed to remove data dir" , "error" , err )
return
}
2024-05-13 13:02:22 +00:00
2024-06-02 18:28:55 +00:00
if err := createDirsFromConfig ( config ) ; err != nil {
logger . Error ( "failed to create directories" , "error" , err )
return
}
2024-05-13 13:02:22 +00:00
2024-06-02 18:28:55 +00:00
request := requests . RestoreAccount {
Mnemonic : * seedPhrase ,
FetchBackup : false ,
CreateAccount : requests . CreateAccount {
2024-08-07 12:59:43 +00:00
DisplayName : "Account1" ,
DeviceName : "StatusIM" ,
Password : * password ,
CustomizationColor : "0x000000" ,
RootDataDir : config . DataDir ,
2024-06-02 18:28:55 +00:00
APIConfig : & requests . APIConfig {
2024-06-26 14:33:22 +00:00
ConnectorEnabled : config . ClusterConfig . Enabled ,
HTTPEnabled : config . HTTPEnabled ,
HTTPHost : config . HTTPHost ,
HTTPPort : config . HTTPPort ,
2024-07-04 10:48:40 +00:00
HTTPVirtualHosts : config . HTTPVirtualHosts ,
2024-06-26 14:33:22 +00:00
WSEnabled : config . WSEnabled ,
WSHost : config . WSHost ,
WSPort : config . WSPort ,
APIModules : config . APIModules ,
2024-06-02 18:28:55 +00:00
} ,
NetworkID : & config . NetworkID ,
TestOverrideNetworks : config . Networks ,
} ,
}
2017-05-03 14:24:48 +00:00
2024-07-04 10:48:40 +00:00
api . OverrideApiConfigTest ( )
2024-06-02 18:28:55 +00:00
_ , err := backend . RestoreAccountAndLogin ( & request )
if err != nil {
logger . Error ( "failed to import account" , "error" , err )
return
}
2024-07-08 14:21:31 +00:00
options := [ ] protocol . Option {
2024-10-06 13:40:22 +00:00
protocol . WithDatabase ( backend . StatusNode ( ) . GetAppDB ( ) ) ,
protocol . WithWalletDatabase ( backend . StatusNode ( ) . GetWalletDB ( ) ) ,
2024-07-08 14:21:31 +00:00
protocol . WithTorrentConfig ( & config . TorrentConfig ) ,
protocol . WithWalletConfig ( & config . WalletConfig ) ,
protocol . WithAccountManager ( backend . AccountManager ( ) ) ,
}
messenger , err := protocol . NewMessenger (
config . Name ,
identity ,
gethbridge . NewNodeBridge ( backend . StatusNode ( ) . GethNode ( ) , backend . StatusNode ( ) . WakuService ( ) , backend . StatusNode ( ) . WakuV2Service ( ) ) ,
installationID . String ( ) ,
nil ,
config . Version ,
options ... ,
)
if err != nil {
logger . Error ( "failed to create messenger" , "error" , err )
return
}
_ , err = messenger . Start ( )
if err != nil {
logger . Error ( "failed to start messenger" , "error" , err )
return
}
interruptCh := haltOnInterruptSignal ( backend . StatusNode ( ) )
go retrieveMessagesLoop ( messenger , 300 * time . Millisecond , interruptCh )
2020-08-20 09:05:39 +00:00
} else {
2024-06-02 18:28:55 +00:00
appDB , walletDB , err := startNode ( config , backend , installationID )
if err != nil {
logger . Error ( "failed to start node" , "error" , err )
return
}
2020-08-20 09:05:39 +00:00
2024-06-02 18:28:55 +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 ( )
}
2020-08-20 09:05:39 +00:00
2024-06-02 18:28:55 +00:00
// handle interrupt signals
interruptCh := haltOnInterruptSignal ( backend . StatusNode ( ) )
2020-08-20 09:05:39 +00:00
2024-06-02 18:28:55 +00:00
// 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 ( )
2020-08-20 07:26:00 +00:00
}
2024-06-02 18:28:55 +00:00
// Check if profiling shall be enabled.
if * pprofEnabled {
profiling . NewProfiler ( * pprofPort ) . Go ( )
2020-08-20 07:26:00 +00:00
}
2024-06-02 18:28:55 +00:00
if config . PushNotificationServerConfig . Enabled {
options := [ ] protocol . Option {
protocol . WithPushNotifications ( ) ,
protocol . WithPushNotificationServerConfig ( & pushnotificationserver . Config {
Enabled : config . PushNotificationServerConfig . Enabled ,
Identity : config . PushNotificationServerConfig . Identity ,
GorushURL : config . PushNotificationServerConfig . GorushURL ,
} ) ,
protocol . WithDatabase ( appDB ) ,
protocol . WithWalletDatabase ( walletDB ) ,
protocol . WithTorrentConfig ( & config . TorrentConfig ) ,
protocol . WithWalletConfig ( & config . WalletConfig ) ,
protocol . WithAccountManager ( backend . AccountManager ( ) ) ,
}
2020-08-20 09:05:39 +00:00
2024-06-02 18:28:55 +00:00
messenger , err := protocol . NewMessenger (
config . Name ,
identity ,
gethbridge . NewNodeBridge ( backend . StatusNode ( ) . GethNode ( ) , backend . StatusNode ( ) . WakuService ( ) , backend . StatusNode ( ) . WakuV2Service ( ) ) ,
installationID . String ( ) ,
nil ,
2024-06-13 22:31:09 +00:00
config . Version ,
2024-06-02 18:28:55 +00:00
options ... ,
)
if err != nil {
logger . Error ( "failed to create messenger" , "error" , err )
return
}
2024-06-10 15:02:42 +00:00
err = messenger . InitInstallations ( )
2024-06-02 18:28:55 +00:00
if err != nil {
2024-06-10 15:02:42 +00:00
logger . Error ( "failed to init messenger installations" , "error" , err )
return
}
err = messenger . InitFilters ( )
if err != nil {
logger . Error ( "failed to init messenger filters" , "error" , err )
2024-06-02 18:28:55 +00:00
return
}
// This will start the push notification server as well as
// the config is set to Enabled
_ , err = messenger . Start ( )
if err != nil {
logger . Error ( "failed to start messenger" , "error" , err )
return
}
go retrieveMessagesLoop ( messenger , 300 * time . Millisecond , interruptCh )
2020-08-20 07:26:00 +00:00
}
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 :
2024-06-10 15:02:42 +00:00
statusd # run regular Whisper node that joins Status network
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
statusd - c . / default . json - log DEBUG -- seed - phrase = "test test test test test test test test test test test junk" -- password = password # run node with configuration specified in . / default . json file , and import account with seed phrase and password
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
}
}
}
2024-05-13 13:02:22 +00:00
func openDatabases ( path string ) ( * sql . DB , * sql . DB , error ) {
walletDB , err := walletdatabase . InitializeDB ( path + "-wallet.db" , "" , dbsetup . ReducedKDFIterationsNumber )
if err != nil {
logger . Error ( "failed to initialize wallet db" , "error" , err )
return nil , nil , err
}
appDB , err := appdatabase . InitializeDB ( path + ".db" , "" , dbsetup . ReducedKDFIterationsNumber )
if err != nil {
logger . Error ( "failed to initialize app db" , "error" , err )
return nil , nil , err
}
return appDB , walletDB , nil
}
func createDirsFromConfig ( config * params . NodeConfig ) error {
// If DataDir is empty, it means we want to create an ephemeral node
// keeping data only in memory.
if config . DataDir != "" {
// make sure data directory exists
if err := os . MkdirAll ( filepath . Clean ( config . DataDir ) , os . ModePerm ) ; err != nil {
return fmt . Errorf ( "make node: make data directory: %v" , err )
}
}
if config . KeyStoreDir != "" {
// make sure keys directory exists
if err := os . MkdirAll ( filepath . Clean ( config . KeyStoreDir ) , os . ModePerm ) ; err != nil {
return fmt . Errorf ( "make node: make keys directory: %v" , err )
}
}
return nil
}
2024-06-02 18:28:55 +00:00
func startNode ( config * params . NodeConfig , backend * api . GethStatusBackend , installationID uuid . UUID ) ( * sql . DB , * sql . DB , error ) {
err := backend . AccountManager ( ) . InitKeystore ( config . KeyStoreDir )
if err != nil {
logger . Error ( "Failed to init keystore" , "error" , err )
return nil , nil , err
}
err = createDirsFromConfig ( config )
if err != nil {
logger . Error ( "failed to create directories" , "error" , err )
return nil , nil , err
}
appDB , walletDB , err := openDatabases ( config . DataDir + "/" + installationID . String ( ) )
if err != nil {
log . Error ( "failed to open databases" )
return nil , nil , err
}
backend . StatusNode ( ) . SetAppDB ( appDB )
backend . StatusNode ( ) . SetWalletDB ( walletDB )
err = backend . StartNode ( config )
if err != nil {
logger . Error ( "Node start failed" , "error" , err )
return nil , nil , err
}
return appDB , walletDB , nil
}