diff --git a/cmd/statusd/main.go b/cmd/statusd/main.go index 677512d2a..5fb4d4a2f 100644 --- a/cmd/statusd/main.go +++ b/cmd/statusd/main.go @@ -5,11 +5,14 @@ import ( "fmt" "log" "os" + "os/signal" "runtime" "strings" + "time" "github.com/status-im/status-go/cmd/statusd/debug" "github.com/status-im/status-go/geth/api" + "github.com/status-im/status-go/geth/common" "github.com/status-im/status-go/geth/params" ) @@ -23,7 +26,8 @@ var ( nodeKeyFile = flag.String("nodekey", "", "P2P node key file (private key)") dataDir = flag.String("datadir", params.DataDir, "Data directory for the databases and keystore") networkID = flag.Int("networkid", params.RopstenNetworkID, "Network identifier (integer, 1=Homestead, 3=Ropsten, 4=Rinkeby, 777=StatusChain)") - whisperEnabled = flag.Bool("shh", false, "SHH protocol enabled") + lesEnabled = flag.Bool("les", false, "LES protocol enabled (default is disabled)") + whisperEnabled = flag.Bool("shh", false, "Whisper protocol enabled (default is disabled)") swarmEnabled = flag.Bool("swarm", false, "Swarm protocol enabled") httpEnabled = flag.Bool("http", false, "HTTP RPC endpoint enabled (default: false)") httpPort = flag.Int("httpport", params.HTTPPort, "HTTP RPC server's listening port") @@ -33,10 +37,10 @@ var ( logLevel = flag.String("log", "INFO", `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE"`) logFile = flag.String("logfile", "", "Path to the log file") version = flag.Bool("version", false, "Print version") - lesEnabled = flag.Bool("les", true, "LES protocol enabled") listenAddr = flag.String("listenaddr", ":30303", "IP address and port of this node (e.g. 127.0.0.1:30303)") standalone = flag.Bool("standalone", true, "Don't actively connect to peers, wait for incoming connections") + bootnodes = flag.String("bootnodes", "", "A list of bootnodes separated by comma") // shh stuff identityFile = flag.String("shh.identityfile", "", "Protocol identity file (private key used for asymmetric encryption)") @@ -74,6 +78,9 @@ func main() { return } + // handle interrupt signals + go haltOnInterruptSignal(backend.NodeManager()) + // wait till node is started <-started @@ -132,6 +139,20 @@ func makeNodeConfig() (*params.NodeConfig, error) { nodeConfig.LightEthConfig.Enabled = *lesEnabled nodeConfig.SwarmConfig.Enabled = *swarmEnabled + if *standalone { + nodeConfig.BootClusterConfig.Enabled = false + nodeConfig.BootClusterConfig.BootNodes = nil + } else { + nodeConfig.Discovery = true + } + + // Even if standalone is true and discovery is disabled, + // it's possible to use bootnodes in NodeManager.PopulateStaticPeers(). + // TODO(adam): research if we need NodeManager.PopulateStaticPeers() at all. + if *bootnodes != "" { + nodeConfig.BootClusterConfig.BootNodes = strings.Split(*bootnodes, ",") + } + if *whisperEnabled { return whisperConfig(nodeConfig) } @@ -184,3 +205,28 @@ Options: fmt.Fprintf(os.Stderr, usage) // nolint: gas flag.PrintDefaults() } + +// haltOnInterruptSignal catches interrupt signal (SIGINT) and +// stops the node. It times out after 5 seconds +// if the node can not be stopped. +func haltOnInterruptSignal(nodeManager common.NodeManager) { + signalCh := make(chan os.Signal, 1) + signal.Notify(signalCh, os.Interrupt) + defer signal.Stop(signalCh) + <-signalCh + + log.Println("Got interrupt, shutting down...") + + nodeStopped, err := nodeManager.StopNode() + if err != nil { + log.Printf("Failed to stop node: %v", err.Error()) + os.Exit(1) + } + + select { + case <-nodeStopped: + case <-time.After(time.Second * 5): + log.Printf("Stopping node timed out") + os.Exit(1) + } +} diff --git a/cmd/statusd/whispercfg.go b/cmd/statusd/whispercfg.go index b99b580c2..d53128361 100644 --- a/cmd/statusd/whispercfg.go +++ b/cmd/statusd/whispercfg.go @@ -64,11 +64,6 @@ func whisperConfig(nodeConfig *params.NodeConfig) (*params.NodeConfig, error) { } nodeConfig.HTTPHost = "0.0.0.0" - if *standalone { - nodeConfig.BootClusterConfig.Enabled = false - nodeConfig.BootClusterConfig.BootNodes = nil - } - return nodeConfig, nil } diff --git a/geth/node/manager.go b/geth/node/manager.go index 01a8de50e..6819ba185 100644 --- a/geth/node/manager.go +++ b/geth/node/manager.go @@ -48,10 +48,7 @@ type NodeManager struct { // NewNodeManager makes new instance of node manager func NewNodeManager() *NodeManager { - m := &NodeManager{} - go HaltOnInterruptSignal(m) // allow interrupting running nodes - - return m + return &NodeManager{} } // StartNode start Status node, fails if node is already started diff --git a/geth/node/node.go b/geth/node/node.go index 43d379ec9..b6fe60e0c 100644 --- a/geth/node/node.go +++ b/geth/node/node.go @@ -17,9 +17,7 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/discover" - "github.com/ethereum/go-ethereum/p2p/discv5" "github.com/ethereum/go-ethereum/p2p/nat" - gethparams "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/whisper/mailserver" "github.com/ethereum/go-ethereum/whisper/notifications" whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" @@ -93,11 +91,11 @@ func defaultEmbeddedNodeConfig(config *params.NodeConfig) *node.Config { Name: config.Name, Version: config.Version, P2P: p2p.Config{ - NoDiscovery: true, + NoDiscovery: !config.Discovery, DiscoveryV5: true, DiscoveryV5Addr: ":0", - BootstrapNodes: makeBootstrapNodes(), - BootstrapNodesV5: makeBootstrapNodesV5(), + BootstrapNodes: nil, + BootstrapNodesV5: nil, ListenAddr: config.ListenAddr, NAT: nat.Any(), MaxPeers: config.MaxPeers, @@ -117,9 +115,8 @@ func defaultEmbeddedNodeConfig(config *params.NodeConfig) *node.Config { nc.HTTPPort = config.HTTPPort } - if !config.BootClusterConfig.Enabled { - nc.P2P.BootstrapNodes = nil - nc.P2P.BootstrapNodesV5 = nil + if config.Discovery { + nc.P2P.BootstrapNodes = makeBootstrapNodes(config.BootClusterConfig.BootNodes) } return nc @@ -215,11 +212,7 @@ func makeWSHost(config *params.NodeConfig) string { } // makeBootstrapNodes returns default (hence bootstrap) list of peers -func makeBootstrapNodes() []*discover.Node { - // on desktops params.TestnetBootnodes and params.MainBootnodes, - // on mobile client we deliberately keep this list empty - enodes := []string{} - +func makeBootstrapNodes(enodes []string) []*discover.Node { var bootstrapNodes []*discover.Node for _, enode := range enodes { bootstrapNodes = append(bootstrapNodes, discover.MustParseNode(enode)) @@ -227,15 +220,3 @@ func makeBootstrapNodes() []*discover.Node { return bootstrapNodes } - -// makeBootstrapNodesV5 returns default (hence bootstrap) list of peers -func makeBootstrapNodesV5() []*discv5.Node { - enodes := gethparams.DiscoveryV5Bootnodes - - var bootstrapNodes []*discv5.Node - for _, enode := range enodes { - bootstrapNodes = append(bootstrapNodes, discv5.MustParseNode(enode)) - } - - return bootstrapNodes -} diff --git a/geth/node/utils.go b/geth/node/utils.go index c3111af03..ec4b2db67 100644 --- a/geth/node/utils.go +++ b/geth/node/utils.go @@ -2,11 +2,8 @@ package node import ( "fmt" - "os" - osSignal "os/signal" "github.com/status-im/status-go/geth/common" - "github.com/status-im/status-go/geth/log" "github.com/status-im/status-go/geth/signal" ) @@ -26,23 +23,3 @@ func HaltOnPanic() { common.Fatalf(err) // os.exit(1) is called internally } } - -// HaltOnInterruptSignal stops node and panics if you press Ctrl-C enough times -func HaltOnInterruptSignal(nodeManager *NodeManager) { - sigc := make(chan os.Signal, 1) - osSignal.Notify(sigc, os.Interrupt) - defer osSignal.Stop(sigc) - <-sigc - if nodeManager.node == nil { - return - } - log.Info("Got interrupt, shutting down...") - go nodeManager.node.Stop() // nolint: errcheck - for i := 3; i > 0; i-- { - <-sigc - if i > 1 { - log.Info(fmt.Sprintf("Already shutting down, interrupt %d more times for panic.", i-1)) - } - } - panic("interrupted!") -} diff --git a/geth/params/config.go b/geth/params/config.go index f73509db1..927c8b911 100644 --- a/geth/params/config.go +++ b/geth/params/config.go @@ -230,6 +230,9 @@ type NodeConfig struct { // remote peer identification as well as network traffic encryption. NodeKeyFile string + // Discovery set to true will enabled discovery protocol. + Discovery bool + // ListenAddr is an IP address and port of this node (e.g. 127.0.0.1:30303). ListenAddr string