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  }