github.com/status-im/status-go@v1.1.0/node/geth_node.go (about)

     1  package node
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  
     9  	"github.com/syndtr/goleveldb/leveldb"
    10  
    11  	"github.com/ethereum/go-ethereum/accounts"
    12  	"github.com/ethereum/go-ethereum/log"
    13  	"github.com/ethereum/go-ethereum/node"
    14  	"github.com/ethereum/go-ethereum/p2p"
    15  	"github.com/ethereum/go-ethereum/p2p/discv5"
    16  	"github.com/ethereum/go-ethereum/p2p/enode"
    17  	"github.com/ethereum/go-ethereum/p2p/nat"
    18  
    19  	"github.com/status-im/status-go/eth-node/crypto"
    20  	"github.com/status-im/status-go/params"
    21  )
    22  
    23  // Errors related to node and services creation.
    24  var (
    25  	ErrNodeMakeFailureFormat                      = "error creating p2p node: %s"
    26  	ErrWakuServiceRegistrationFailure             = errors.New("failed to register the Waku service")
    27  	ErrWakuV2ServiceRegistrationFailure           = errors.New("failed to register the WakuV2 service")
    28  	ErrLightEthRegistrationFailure                = errors.New("failed to register the LES service")
    29  	ErrLightEthRegistrationFailureUpstreamEnabled = errors.New("failed to register the LES service, upstream is also configured")
    30  	ErrPersonalServiceRegistrationFailure         = errors.New("failed to register the personal api service")
    31  	ErrStatusServiceRegistrationFailure           = errors.New("failed to register the Status service")
    32  	ErrPeerServiceRegistrationFailure             = errors.New("failed to register the Peer service")
    33  )
    34  
    35  // All general log messages in this package should be routed through this logger.
    36  var logger = log.New("package", "status-go/node")
    37  
    38  // MakeNode creates a geth node entity
    39  func MakeNode(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB) (*node.Node, error) {
    40  	// If DataDir is empty, it means we want to create an ephemeral node
    41  	// keeping data only in memory.
    42  	if config.DataDir != "" {
    43  		// make sure data directory exists
    44  		if err := os.MkdirAll(filepath.Clean(config.DataDir), os.ModePerm); err != nil {
    45  			return nil, fmt.Errorf("make node: make data directory: %v", err)
    46  		}
    47  
    48  		// make sure keys directory exists
    49  		if err := os.MkdirAll(filepath.Clean(config.KeyStoreDir), os.ModePerm); err != nil {
    50  			return nil, fmt.Errorf("make node: make keys directory: %v", err)
    51  		}
    52  	}
    53  
    54  	stackConfig, err := newGethNodeConfig(config)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	stack, err := node.New(stackConfig)
    60  	if err != nil {
    61  		return nil, fmt.Errorf(ErrNodeMakeFailureFormat, err.Error())
    62  	}
    63  
    64  	return stack, nil
    65  }
    66  
    67  // newGethNodeConfig returns default stack configuration for mobile client node
    68  func newGethNodeConfig(config *params.NodeConfig) (*node.Config, error) {
    69  	// NOTE: I haven't changed anything related to this parameters, but
    70  	// it seems they were previously ignored if set to 0, but now they seem
    71  	// to be used, so they need to be set to something
    72  	maxPeers := 100
    73  	maxPendingPeers := 100
    74  
    75  	if config.MaxPeers != 0 {
    76  		maxPeers = config.MaxPeers
    77  	}
    78  
    79  	if config.MaxPendingPeers != 0 {
    80  		maxPendingPeers = config.MaxPendingPeers
    81  	}
    82  
    83  	nc := &node.Config{
    84  		DataDir:           config.DataDir,
    85  		KeyStoreDir:       config.KeyStoreDir,
    86  		UseLightweightKDF: true,
    87  		NoUSB:             true,
    88  		Name:              config.Name,
    89  		Version:           config.Version,
    90  		P2P: p2p.Config{
    91  			NoDiscovery:     true, // we always use only v5 server
    92  			ListenAddr:      config.ListenAddr,
    93  			NAT:             nat.Any(),
    94  			MaxPeers:        maxPeers,
    95  			MaxPendingPeers: maxPendingPeers,
    96  		},
    97  	}
    98  
    99  	if config.IPCEnabled {
   100  		// use well-known defaults
   101  		if config.IPCFile == "" {
   102  			config.IPCFile = "geth.ipc"
   103  		}
   104  
   105  		nc.IPCPath = config.IPCFile
   106  	}
   107  
   108  	if config.HTTPEnabled {
   109  		nc.HTTPModules = config.FormatAPIModules()
   110  		nc.HTTPHost = config.HTTPHost
   111  		nc.HTTPPort = config.HTTPPort
   112  		nc.HTTPVirtualHosts = config.HTTPVirtualHosts
   113  		nc.HTTPCors = config.HTTPCors
   114  	}
   115  
   116  	if config.WSEnabled {
   117  		nc.WSModules = config.FormatAPIModules()
   118  		nc.WSHost = config.WSHost
   119  		nc.WSPort = config.WSPort
   120  		// FIXME: this is a temporary solution to allow all origins
   121  		nc.WSOrigins = []string{"*"}
   122  	}
   123  
   124  	if config.ClusterConfig.Enabled {
   125  		nc.P2P.BootstrapNodesV5 = parseNodesV5(config.ClusterConfig.BootNodes)
   126  		nc.P2P.StaticNodes = parseNodes(config.ClusterConfig.StaticNodes)
   127  	}
   128  
   129  	if config.NodeKey != "" {
   130  		sk, err := crypto.HexToECDSA(config.NodeKey)
   131  		if err != nil {
   132  			return nil, err
   133  		}
   134  		// override node's private key
   135  		nc.P2P.PrivateKey = sk
   136  	}
   137  
   138  	return nc, nil
   139  }
   140  
   141  // parseNodes creates list of enode.Node out of enode strings.
   142  func parseNodes(enodes []string) []*enode.Node {
   143  	var nodes []*enode.Node
   144  	for _, item := range enodes {
   145  		parsedPeer, err := enode.ParseV4(item)
   146  		if err == nil {
   147  			nodes = append(nodes, parsedPeer)
   148  		} else {
   149  			logger.Error("Failed to parse enode", "enode", item, "err", err)
   150  		}
   151  
   152  	}
   153  	return nodes
   154  }
   155  
   156  // parseNodesV5 creates list of discv5.Node out of enode strings.
   157  func parseNodesV5(enodes []string) []*discv5.Node {
   158  	var nodes []*discv5.Node
   159  	for _, enode := range enodes {
   160  		parsedPeer, err := discv5.ParseNode(enode)
   161  
   162  		if err == nil {
   163  			nodes = append(nodes, parsedPeer)
   164  		} else {
   165  			logger.Error("Failed to parse enode", "enode", enode, "err", err)
   166  		}
   167  	}
   168  	return nodes
   169  }
   170  
   171  func parseNodesToNodeID(enodes []string) []enode.ID {
   172  	nodeIDs := make([]enode.ID, 0, len(enodes))
   173  	for _, node := range parseNodes(enodes) {
   174  		nodeIDs = append(nodeIDs, node.ID())
   175  	}
   176  	return nodeIDs
   177  }