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 }