github.com/theQRL/go-zond@v0.1.1/node/config.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package node 18 19 import ( 20 "crypto/ecdsa" 21 "fmt" 22 "net" 23 "os" 24 "path/filepath" 25 "runtime" 26 "strings" 27 28 "github.com/theQRL/go-zond/common" 29 "github.com/theQRL/go-zond/crypto" 30 "github.com/theQRL/go-zond/log" 31 "github.com/theQRL/go-zond/p2p" 32 "github.com/theQRL/go-zond/rpc" 33 ) 34 35 const ( 36 datadirPrivateKey = "nodekey" // Path within the datadir to the node's private key 37 datadirJWTKey = "jwtsecret" // Path within the datadir to the node's jwt secret 38 datadirDefaultKeyStore = "keystore" // Path within the datadir to the keystore 39 datadirStaticNodes = "static-nodes.json" // Path within the datadir to the static node list 40 datadirTrustedNodes = "trusted-nodes.json" // Path within the datadir to the trusted node list 41 datadirNodeDatabase = "nodes" // Path within the datadir to store the node infos 42 ) 43 44 // Config represents a small collection of configuration values to fine tune the 45 // P2P network layer of a protocol stack. These values can be further extended by 46 // all registered services. 47 type Config struct { 48 // Name sets the instance name of the node. It must not contain the / character and is 49 // used in the devp2p node identifier. The instance name of gzond is "gzond". If no 50 // value is specified, the basename of the current executable is used. 51 Name string `toml:"-"` 52 53 // UserIdent, if set, is used as an additional component in the devp2p node identifier. 54 UserIdent string `toml:",omitempty"` 55 56 // Version should be set to the version number of the program. It is used 57 // in the devp2p node identifier. 58 Version string `toml:"-"` 59 60 // DataDir is the file system folder the node should use for any data storage 61 // requirements. The configured data directory will not be directly shared with 62 // registered services, instead those can use utility methods to create/access 63 // databases or flat files. This enables ephemeral nodes which can fully reside 64 // in memory. 65 DataDir string 66 67 // Configuration of peer-to-peer networking. 68 P2P p2p.Config 69 70 // KeyStoreDir is the file system folder that contains private keys. The directory can 71 // be specified as a relative path, in which case it is resolved relative to the 72 // current directory. 73 // 74 // If KeyStoreDir is empty, the default location is the "keystore" subdirectory of 75 // DataDir. If DataDir is unspecified and KeyStoreDir is empty, an ephemeral directory 76 // is created by New and destroyed when the node is stopped. 77 KeyStoreDir string `toml:",omitempty"` 78 79 // ExternalSigner specifies an external URI for a clef-type signer. 80 ExternalSigner string `toml:",omitempty"` 81 82 // UseLightweightKDF lowers the memory and CPU requirements of the key store 83 // scrypt KDF at the expense of security. 84 UseLightweightKDF bool `toml:",omitempty"` 85 86 // InsecureUnlockAllowed allows user to unlock accounts in unsafe http environment. 87 InsecureUnlockAllowed bool `toml:",omitempty"` 88 89 // NoUSB disables hardware wallet monitoring and connectivity. 90 // Deprecated: USB monitoring is disabled by default and must be enabled explicitly. 91 NoUSB bool `toml:",omitempty"` 92 93 // USB enables hardware wallet monitoring and connectivity. 94 USB bool `toml:",omitempty"` 95 96 // SmartCardDaemonPath is the path to the smartcard daemon's socket. 97 SmartCardDaemonPath string `toml:",omitempty"` 98 99 // IPCPath is the requested location to place the IPC endpoint. If the path is 100 // a simple file name, it is placed inside the data directory (or on the root 101 // pipe path on Windows), whereas if it's a resolvable path name (absolute or 102 // relative), then that specific path is enforced. An empty path disables IPC. 103 IPCPath string 104 105 // HTTPHost is the host interface on which to start the HTTP RPC server. If this 106 // field is empty, no HTTP API endpoint will be started. 107 HTTPHost string 108 109 // HTTPPort is the TCP port number on which to start the HTTP RPC server. The 110 // default zero value is/ valid and will pick a port number randomly (useful 111 // for ephemeral nodes). 112 HTTPPort int `toml:",omitempty"` 113 114 // HTTPCors is the Cross-Origin Resource Sharing header to send to requesting 115 // clients. Please be aware that CORS is a browser enforced security, it's fully 116 // useless for custom HTTP clients. 117 HTTPCors []string `toml:",omitempty"` 118 119 // HTTPVirtualHosts is the list of virtual hostnames which are allowed on incoming requests. 120 // This is by default {'localhost'}. Using this prevents attacks like 121 // DNS rebinding, which bypasses SOP by simply masquerading as being within the same 122 // origin. These attacks do not utilize CORS, since they are not cross-domain. 123 // By explicitly checking the Host-header, the server will not allow requests 124 // made against the server with a malicious host domain. 125 // Requests using ip address directly are not affected 126 HTTPVirtualHosts []string `toml:",omitempty"` 127 128 // HTTPModules is a list of API modules to expose via the HTTP RPC interface. 129 // If the module list is empty, all RPC API endpoints designated public will be 130 // exposed. 131 HTTPModules []string 132 133 // HTTPTimeouts allows for customization of the timeout values used by the HTTP RPC 134 // interface. 135 HTTPTimeouts rpc.HTTPTimeouts 136 137 // HTTPPathPrefix specifies a path prefix on which http-rpc is to be served. 138 HTTPPathPrefix string `toml:",omitempty"` 139 140 // AuthAddr is the listening address on which authenticated APIs are provided. 141 AuthAddr string `toml:",omitempty"` 142 143 // AuthPort is the port number on which authenticated APIs are provided. 144 AuthPort int `toml:",omitempty"` 145 146 // AuthVirtualHosts is the list of virtual hostnames which are allowed on incoming requests 147 // for the authenticated api. This is by default {'localhost'}. 148 AuthVirtualHosts []string `toml:",omitempty"` 149 150 // WSHost is the host interface on which to start the websocket RPC server. If 151 // this field is empty, no websocket API endpoint will be started. 152 WSHost string 153 154 // WSPort is the TCP port number on which to start the websocket RPC server. The 155 // default zero value is/ valid and will pick a port number randomly (useful for 156 // ephemeral nodes). 157 WSPort int `toml:",omitempty"` 158 159 // WSPathPrefix specifies a path prefix on which ws-rpc is to be served. 160 WSPathPrefix string `toml:",omitempty"` 161 162 // WSOrigins is the list of domain to accept websocket requests from. Please be 163 // aware that the server can only act upon the HTTP request the client sends and 164 // cannot verify the validity of the request header. 165 WSOrigins []string `toml:",omitempty"` 166 167 // WSModules is a list of API modules to expose via the websocket RPC interface. 168 // If the module list is empty, all RPC API endpoints designated public will be 169 // exposed. 170 WSModules []string 171 172 // WSExposeAll exposes all API modules via the WebSocket RPC interface rather 173 // than just the public ones. 174 // 175 // *WARNING* Only set this if the node is running in a trusted network, exposing 176 // private APIs to untrusted users is a major security risk. 177 WSExposeAll bool `toml:",omitempty"` 178 179 // GraphQLCors is the Cross-Origin Resource Sharing header to send to requesting 180 // clients. Please be aware that CORS is a browser enforced security, it's fully 181 // useless for custom HTTP clients. 182 GraphQLCors []string `toml:",omitempty"` 183 184 // GraphQLVirtualHosts is the list of virtual hostnames which are allowed on incoming requests. 185 // This is by default {'localhost'}. Using this prevents attacks like 186 // DNS rebinding, which bypasses SOP by simply masquerading as being within the same 187 // origin. These attacks do not utilize CORS, since they are not cross-domain. 188 // By explicitly checking the Host-header, the server will not allow requests 189 // made against the server with a malicious host domain. 190 // Requests using ip address directly are not affected 191 GraphQLVirtualHosts []string `toml:",omitempty"` 192 193 // Logger is a custom logger to use with the p2p.Server. 194 Logger log.Logger `toml:",omitempty"` 195 196 oldGethResourceWarning bool 197 198 // AllowUnprotectedTxs allows non EIP-155 protected transactions to be send over RPC. 199 AllowUnprotectedTxs bool `toml:",omitempty"` 200 201 // BatchRequestLimit is the maximum number of requests in a batch. 202 BatchRequestLimit int `toml:",omitempty"` 203 204 // BatchResponseMaxSize is the maximum number of bytes returned from a batched rpc call. 205 BatchResponseMaxSize int `toml:",omitempty"` 206 207 // JWTSecret is the path to the hex-encoded jwt secret. 208 JWTSecret string `toml:",omitempty"` 209 210 // EnablePersonal enables the deprecated personal namespace. 211 EnablePersonal bool `toml:"-"` 212 213 DBEngine string `toml:",omitempty"` 214 } 215 216 // IPCEndpoint resolves an IPC endpoint based on a configured value, taking into 217 // account the set data folders as well as the designated platform we're currently 218 // running on. 219 func (c *Config) IPCEndpoint() string { 220 // Short circuit if IPC has not been enabled 221 if c.IPCPath == "" { 222 return "" 223 } 224 // On windows we can only use plain top-level pipes 225 if runtime.GOOS == "windows" { 226 if strings.HasPrefix(c.IPCPath, `\\.\pipe\`) { 227 return c.IPCPath 228 } 229 return `\\.\pipe\` + c.IPCPath 230 } 231 // Resolve names into the data directory full paths otherwise 232 if filepath.Base(c.IPCPath) == c.IPCPath { 233 if c.DataDir == "" { 234 return filepath.Join(os.TempDir(), c.IPCPath) 235 } 236 return filepath.Join(c.DataDir, c.IPCPath) 237 } 238 return c.IPCPath 239 } 240 241 // NodeDB returns the path to the discovery node database. 242 func (c *Config) NodeDB() string { 243 if c.DataDir == "" { 244 return "" // ephemeral 245 } 246 return c.ResolvePath(datadirNodeDatabase) 247 } 248 249 // DefaultIPCEndpoint returns the IPC path used by default. 250 func DefaultIPCEndpoint(clientIdentifier string) string { 251 if clientIdentifier == "" { 252 clientIdentifier = strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") 253 if clientIdentifier == "" { 254 panic("empty executable name") 255 } 256 } 257 config := &Config{DataDir: DefaultDataDir(), IPCPath: clientIdentifier + ".ipc"} 258 return config.IPCEndpoint() 259 } 260 261 // HTTPEndpoint resolves an HTTP endpoint based on the configured host interface 262 // and port parameters. 263 func (c *Config) HTTPEndpoint() string { 264 if c.HTTPHost == "" { 265 return "" 266 } 267 return net.JoinHostPort(c.HTTPHost, fmt.Sprintf("%d", c.HTTPPort)) 268 } 269 270 // DefaultHTTPEndpoint returns the HTTP endpoint used by default. 271 func DefaultHTTPEndpoint() string { 272 config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort, AuthPort: DefaultAuthPort} 273 return config.HTTPEndpoint() 274 } 275 276 // WSEndpoint resolves a websocket endpoint based on the configured host interface 277 // and port parameters. 278 func (c *Config) WSEndpoint() string { 279 if c.WSHost == "" { 280 return "" 281 } 282 return net.JoinHostPort(c.WSHost, fmt.Sprintf("%d", c.WSPort)) 283 } 284 285 // DefaultWSEndpoint returns the websocket endpoint used by default. 286 func DefaultWSEndpoint() string { 287 config := &Config{WSHost: DefaultWSHost, WSPort: DefaultWSPort} 288 return config.WSEndpoint() 289 } 290 291 // ExtRPCEnabled returns the indicator whether node enables the external 292 // RPC(http, ws or graphql). 293 func (c *Config) ExtRPCEnabled() bool { 294 return c.HTTPHost != "" || c.WSHost != "" 295 } 296 297 // NodeName returns the devp2p node identifier. 298 func (c *Config) NodeName() string { 299 name := c.name() 300 // Backwards compatibility: previous versions used title-cased "Gzond", keep that. 301 if name == "gzond" || name == "gzond-testnet" { 302 name = "Gzond" 303 } 304 if c.UserIdent != "" { 305 name += "/" + c.UserIdent 306 } 307 if c.Version != "" { 308 name += "/v" + c.Version 309 } 310 name += "/" + runtime.GOOS + "-" + runtime.GOARCH 311 name += "/" + runtime.Version() 312 return name 313 } 314 315 func (c *Config) name() string { 316 if c.Name == "" { 317 progname := strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") 318 if progname == "" { 319 panic("empty executable name, set Config.Name") 320 } 321 return progname 322 } 323 return c.Name 324 } 325 326 // These resources are resolved differently for "gzond" instances. 327 var isOldGethResource = map[string]bool{ 328 "chaindata": true, 329 "nodes": true, 330 "nodekey": true, 331 "static-nodes.json": false, // no warning for these because they have their 332 "trusted-nodes.json": false, // own separate warning. 333 } 334 335 // ResolvePath resolves path in the instance directory. 336 func (c *Config) ResolvePath(path string) string { 337 if filepath.IsAbs(path) { 338 return path 339 } 340 if c.DataDir == "" { 341 return "" 342 } 343 // Backwards-compatibility: ensure that data directory files created 344 // by geth 1.4 are used if they exist. 345 if warn, isOld := isOldGethResource[path]; isOld { 346 oldpath := "" 347 if c.name() == "gzond" { 348 oldpath = filepath.Join(c.DataDir, path) 349 } 350 if oldpath != "" && common.FileExist(oldpath) { 351 if warn && !c.oldGethResourceWarning { 352 c.oldGethResourceWarning = true 353 log.Warn("Using deprecated resource file, please move this file to the 'geth' subdirectory of datadir.", "file", oldpath) 354 } 355 return oldpath 356 } 357 } 358 return filepath.Join(c.instanceDir(), path) 359 } 360 361 func (c *Config) instanceDir() string { 362 if c.DataDir == "" { 363 return "" 364 } 365 return filepath.Join(c.DataDir, c.name()) 366 } 367 368 // NodeKey retrieves the currently configured private key of the node, checking 369 // first any manually set key, falling back to the one found in the configured 370 // data folder. If no key can be found, a new one is generated. 371 func (c *Config) NodeKey() *ecdsa.PrivateKey { 372 // Use any specifically configured key. 373 if c.P2P.PrivateKey != nil { 374 return c.P2P.PrivateKey 375 } 376 // Generate ephemeral key if no datadir is being used. 377 if c.DataDir == "" { 378 key, err := crypto.GenerateKey() 379 if err != nil { 380 log.Crit(fmt.Sprintf("Failed to generate ephemeral node key: %v", err)) 381 } 382 return key 383 } 384 385 keyfile := c.ResolvePath(datadirPrivateKey) 386 if key, err := crypto.LoadECDSA(keyfile); err == nil { 387 return key 388 } 389 // No persistent key found, generate and store a new one. 390 key, err := crypto.GenerateKey() 391 if err != nil { 392 log.Crit(fmt.Sprintf("Failed to generate node key: %v", err)) 393 } 394 instanceDir := filepath.Join(c.DataDir, c.name()) 395 if err := os.MkdirAll(instanceDir, 0700); err != nil { 396 log.Error(fmt.Sprintf("Failed to persist node key: %v", err)) 397 return key 398 } 399 keyfile = filepath.Join(instanceDir, datadirPrivateKey) 400 if err := crypto.SaveECDSA(keyfile, key); err != nil { 401 log.Error(fmt.Sprintf("Failed to persist node key: %v", err)) 402 } 403 return key 404 } 405 406 // checkLegacyFiles inspects the datadir for signs of legacy static-nodes 407 // and trusted-nodes files. If they exist it raises an error. 408 func (c *Config) checkLegacyFiles() { 409 c.checkLegacyFile(c.ResolvePath(datadirStaticNodes)) 410 c.checkLegacyFile(c.ResolvePath(datadirTrustedNodes)) 411 } 412 413 // checkLegacyFile will only raise an error if a file at the given path exists. 414 func (c *Config) checkLegacyFile(path string) { 415 // Short circuit if no node config is present 416 if c.DataDir == "" { 417 return 418 } 419 if _, err := os.Stat(path); err != nil { 420 return 421 } 422 logger := c.Logger 423 if logger == nil { 424 logger = log.Root() 425 } 426 switch fname := filepath.Base(path); fname { 427 case "static-nodes.json": 428 logger.Error("The static-nodes.json file is deprecated and ignored. Use P2P.StaticNodes in config.toml instead.") 429 case "trusted-nodes.json": 430 logger.Error("The trusted-nodes.json file is deprecated and ignored. Use P2P.TrustedNodes in config.toml instead.") 431 default: 432 // We shouldn't wind up here, but better print something just in case. 433 logger.Error("Ignoring deprecated file.", "file", path) 434 } 435 } 436 437 // KeyDirConfig determines the settings for keydirectory 438 func (c *Config) KeyDirConfig() (string, error) { 439 var ( 440 keydir string 441 err error 442 ) 443 switch { 444 case filepath.IsAbs(c.KeyStoreDir): 445 keydir = c.KeyStoreDir 446 case c.DataDir != "": 447 if c.KeyStoreDir == "" { 448 keydir = filepath.Join(c.DataDir, datadirDefaultKeyStore) 449 } else { 450 keydir, err = filepath.Abs(c.KeyStoreDir) 451 } 452 case c.KeyStoreDir != "": 453 keydir, err = filepath.Abs(c.KeyStoreDir) 454 } 455 return keydir, err 456 } 457 458 // GetKeyStoreDir retrieves the key directory and will create 459 // and ephemeral one if necessary. 460 func (c *Config) GetKeyStoreDir() (string, bool, error) { 461 keydir, err := c.KeyDirConfig() 462 if err != nil { 463 return "", false, err 464 } 465 isEphemeral := false 466 if keydir == "" { 467 // There is no datadir. 468 keydir, err = os.MkdirTemp("", "go-ethereum-keystore") 469 isEphemeral = true 470 } 471 472 if err != nil { 473 return "", false, err 474 } 475 if err := os.MkdirAll(keydir, 0700); err != nil { 476 return "", false, err 477 } 478 479 return keydir, isEphemeral, nil 480 }