github.com/status-im/status-go@v1.1.0/cmd/node-canary/main.go (about) 1 // node-canary tests whether a P2P peer is responding correctly. 2 package main 3 4 import ( 5 "flag" 6 stdlog "log" 7 "os" 8 "path" 9 "path/filepath" 10 "time" 11 12 "golang.org/x/crypto/ssh/terminal" 13 14 "github.com/ethereum/go-ethereum/log" 15 "github.com/ethereum/go-ethereum/p2p" 16 "github.com/ethereum/go-ethereum/p2p/enode" 17 18 "github.com/status-im/status-go/api" 19 "github.com/status-im/status-go/logutils" 20 "github.com/status-im/status-go/params" 21 "github.com/status-im/status-go/t/helpers" 22 ) 23 24 // All general log messages in this package should be routed through this logger. 25 var logger = log.New("package", "status-go/cmd/node-canary") 26 27 var ( 28 staticEnodeAddr = flag.String("staticnode", "", "checks if static node talks waku protocol (e.g. enode://abc123@1.2.3.4:30303)") 29 minPow = flag.Float64("waku.pow", params.WakuMinimumPoW, "PoW for messages to be added to queue, in float format") 30 ttl = flag.Int("waku.ttl", params.WakuTTL, "Time to live for messages, in seconds") 31 homePath = flag.String("home-dir", ".", "Home directory where state is stored") 32 logLevel = flag.String("log", "INFO", `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE"`) 33 logFile = flag.String("logfile", "", "Path to the log file") 34 logWithoutColors = flag.Bool("log-without-color", false, "Disables log colors") 35 ) 36 37 func main() { 38 var err error 39 var staticParsedNode *enode.Node 40 if *staticEnodeAddr != "" { 41 staticParsedNode, err = enode.ParseV4(*staticEnodeAddr) 42 if err != nil { 43 logger.Crit("Invalid static address specified", "staticEnodeAddr", *staticEnodeAddr, "error", err) 44 os.Exit(1) 45 } 46 } 47 48 if staticParsedNode != nil { 49 verifyStaticNodeBehavior(staticParsedNode) 50 logger.Info("Connected to static node correctly", "address", *staticEnodeAddr) 51 os.Exit(0) 52 } 53 54 logger.Crit("No address specified") 55 os.Exit(1) 56 } 57 58 func init() { 59 flag.Parse() 60 61 colors := !(*logWithoutColors) 62 if colors { 63 colors = terminal.IsTerminal(int(os.Stdin.Fd())) 64 } 65 66 if err := logutils.OverrideRootLog(*logLevel != "", *logLevel, logutils.FileOptions{Filename: *logFile}, colors); err != nil { 67 stdlog.Fatalf("Error initializing logger: %s", err) 68 } 69 } 70 71 func verifyStaticNodeBehavior(staticNode *enode.Node) { 72 clientBackend, err := startClientNode() 73 if err != nil { 74 logger.Error("Node start failed", "error", err) 75 os.Exit(1) 76 } 77 defer func() { _ = clientBackend.StopNode() }() 78 79 clientNode := clientBackend.StatusNode() 80 81 // wait for peer to be added to client 82 clientErrCh := helpers.WaitForPeerAsync(clientNode.Server(), *staticEnodeAddr, p2p.PeerEventTypeAdd, 5*time.Second) 83 err = <-clientErrCh 84 if err != nil { 85 logger.Error("Error detected while waiting for static peer to be added", "error", err) 86 os.Exit(1) 87 } 88 89 // wait to check if peer remains connected to client 90 clientErrCh = helpers.WaitForPeerAsync(clientNode.Server(), *staticEnodeAddr, p2p.PeerEventTypeDrop, 5*time.Second) 91 err = <-clientErrCh 92 peers := clientNode.GethNode().Server().Peers() 93 if len(peers) != 1 { 94 logger.Error("Failed to add static peer", "error", err) 95 os.Exit(1) 96 } 97 } 98 99 // makeNodeConfig parses incoming CLI options and returns node configuration object 100 func makeNodeConfig() (*params.NodeConfig, error) { 101 err := error(nil) 102 103 workDir := "" 104 if path.IsAbs(*homePath) { 105 workDir = *homePath 106 } else { 107 workDir, err = filepath.Abs(filepath.Dir(os.Args[0])) 108 if err == nil { 109 workDir = path.Join(workDir, *homePath) 110 } 111 } 112 if err != nil { 113 return nil, err 114 } 115 116 nodeConfig, err := params.NewNodeConfigWithDefaults(path.Join(workDir, ".ethereum"), uint64(params.GoerliNetworkID)) 117 if err != nil { 118 return nil, err 119 } 120 121 if *logLevel != "" { 122 nodeConfig.LogLevel = *logLevel 123 nodeConfig.LogEnabled = true 124 } 125 126 if *logFile != "" { 127 nodeConfig.LogFile = *logFile 128 } 129 130 nodeConfig.NoDiscovery = true 131 nodeConfig.ListenAddr = "" 132 if *staticEnodeAddr != "" { 133 nodeConfig.ClusterConfig.Enabled = true 134 nodeConfig.ClusterConfig.Fleet = params.FleetUndefined 135 nodeConfig.ClusterConfig.StaticNodes = []string{ 136 *staticEnodeAddr, 137 } 138 } 139 140 return wakuConfig(nodeConfig) 141 } 142 143 // wakuConfig creates node configuration object from flags 144 func wakuConfig(nodeConfig *params.NodeConfig) (*params.NodeConfig, error) { 145 wakuConfig := &nodeConfig.WakuConfig 146 wakuConfig.Enabled = true 147 wakuConfig.LightClient = true 148 wakuConfig.MinimumPoW = *minPow 149 wakuConfig.TTL = *ttl 150 151 return nodeConfig, nil 152 } 153 154 func startClientNode() (*api.GethStatusBackend, error) { 155 config, err := makeNodeConfig() 156 if err != nil { 157 return nil, err 158 } 159 clientBackend := api.NewGethStatusBackend() 160 err = clientBackend.AccountManager().InitKeystore(config.KeyStoreDir) 161 if err != nil { 162 return nil, err 163 } 164 err = clientBackend.StartNode(config) 165 if err != nil { 166 return nil, err 167 } 168 return clientBackend, err 169 }