github.com/phillinzzz/newBsc@v1.1.6/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 "io/ioutil" 23 "os" 24 "path/filepath" 25 "runtime" 26 "strings" 27 "sync" 28 29 "github.com/phillinzzz/newBsc/accounts" 30 "github.com/phillinzzz/newBsc/accounts/external" 31 "github.com/phillinzzz/newBsc/accounts/keystore" 32 "github.com/phillinzzz/newBsc/accounts/scwallet" 33 "github.com/phillinzzz/newBsc/accounts/usbwallet" 34 "github.com/phillinzzz/newBsc/common" 35 "github.com/phillinzzz/newBsc/crypto" 36 "github.com/phillinzzz/newBsc/log" 37 "github.com/phillinzzz/newBsc/p2p" 38 "github.com/phillinzzz/newBsc/p2p/enode" 39 "github.com/phillinzzz/newBsc/rpc" 40 ) 41 42 const ( 43 datadirPrivateKey = "nodekey" // Path within the datadir to the node's private key 44 datadirDefaultKeyStore = "keystore" // Path within the datadir to the keystore 45 datadirStaticNodes = "static-nodes.json" // Path within the datadir to the static node list 46 datadirTrustedNodes = "trusted-nodes.json" // Path within the datadir to the trusted node list 47 datadirNodeDatabase = "nodes" // Path within the datadir to store the node infos 48 ) 49 50 // Config represents a small collection of configuration values to fine tune the 51 // P2P network layer of a protocol stack. These values can be further extended by 52 // all registered services. 53 type Config struct { 54 // Name sets the instance name of the node. It must not contain the / character and is 55 // used in the devp2p node identifier. The instance name of geth is "geth". If no 56 // value is specified, the basename of the current executable is used. 57 Name string `toml:"-"` 58 59 // UserIdent, if set, is used as an additional component in the devp2p node identifier. 60 UserIdent string `toml:",omitempty"` 61 62 // Version should be set to the version number of the program. It is used 63 // in the devp2p node identifier. 64 Version string `toml:"-"` 65 66 // DataDir is the file system folder the node should use for any data storage 67 // requirements. The configured data directory will not be directly shared with 68 // registered services, instead those can use utility methods to create/access 69 // databases or flat files. This enables ephemeral nodes which can fully reside 70 // in memory. 71 DataDir string 72 73 // Configuration of peer-to-peer networking. 74 P2P p2p.Config 75 76 // KeyStoreDir is the file system folder that contains private keys. The directory can 77 // be specified as a relative path, in which case it is resolved relative to the 78 // current directory. 79 // 80 // If KeyStoreDir is empty, the default location is the "keystore" subdirectory of 81 // DataDir. If DataDir is unspecified and KeyStoreDir is empty, an ephemeral directory 82 // is created by New and destroyed when the node is stopped. 83 KeyStoreDir string `toml:",omitempty"` 84 85 // ExternalSigner specifies an external URI for a clef-type signer 86 ExternalSigner string `toml:",omitempty"` 87 88 // UseLightweightKDF lowers the memory and CPU requirements of the key store 89 // scrypt KDF at the expense of security. 90 UseLightweightKDF bool `toml:",omitempty"` 91 92 // InsecureUnlockAllowed allows user to unlock accounts in unsafe http environment. 93 InsecureUnlockAllowed bool `toml:",omitempty"` 94 95 // NoUSB disables hardware wallet monitoring and connectivity. 96 NoUSB bool `toml:",omitempty"` 97 98 // DirectBroadcast enable directly broadcast mined block to all peers 99 DirectBroadcast bool `toml:",omitempty"` 100 101 // DisableSnapProtocol disable the snap protocol 102 DisableSnapProtocol bool `toml:",omitempty"` 103 104 // RangeLimit enable 5000 blocks limit when handle range query 105 RangeLimit bool `toml:",omitempty"` 106 107 // USB enables hardware wallet monitoring and connectivity. 108 USB bool `toml:",omitempty"` 109 110 // SmartCardDaemonPath is the path to the smartcard daemon's socket 111 SmartCardDaemonPath string `toml:",omitempty"` 112 113 // IPCPath is the requested location to place the IPC endpoint. If the path is 114 // a simple file name, it is placed inside the data directory (or on the root 115 // pipe path on Windows), whereas if it's a resolvable path name (absolute or 116 // relative), then that specific path is enforced. An empty path disables IPC. 117 IPCPath string 118 119 // HTTPHost is the host interface on which to start the HTTP RPC server. If this 120 // field is empty, no HTTP API endpoint will be started. 121 HTTPHost string 122 123 // HTTPPort is the TCP port number on which to start the HTTP RPC server. The 124 // default zero value is/ valid and will pick a port number randomly (useful 125 // for ephemeral nodes). 126 HTTPPort int `toml:",omitempty"` 127 128 // HTTPCors is the Cross-Origin Resource Sharing header to send to requesting 129 // clients. Please be aware that CORS is a browser enforced security, it's fully 130 // useless for custom HTTP clients. 131 HTTPCors []string `toml:",omitempty"` 132 133 // HTTPVirtualHosts is the list of virtual hostnames which are allowed on incoming requests. 134 // This is by default {'localhost'}. Using this prevents attacks like 135 // DNS rebinding, which bypasses SOP by simply masquerading as being within the same 136 // origin. These attacks do not utilize CORS, since they are not cross-domain. 137 // By explicitly checking the Host-header, the server will not allow requests 138 // made against the server with a malicious host domain. 139 // Requests using ip address directly are not affected 140 HTTPVirtualHosts []string `toml:",omitempty"` 141 142 // HTTPModules is a list of API modules to expose via the HTTP RPC interface. 143 // If the module list is empty, all RPC API endpoints designated public will be 144 // exposed. 145 HTTPModules []string 146 147 // HTTPTimeouts allows for customization of the timeout values used by the HTTP RPC 148 // interface. 149 HTTPTimeouts rpc.HTTPTimeouts 150 151 // HTTPPathPrefix specifies a path prefix on which http-rpc is to be served. 152 HTTPPathPrefix string `toml:",omitempty"` 153 154 // WSHost is the host interface on which to start the websocket RPC server. If 155 // this field is empty, no websocket API endpoint will be started. 156 WSHost string 157 158 // WSPort is the TCP port number on which to start the websocket RPC server. The 159 // default zero value is/ valid and will pick a port number randomly (useful for 160 // ephemeral nodes). 161 WSPort int `toml:",omitempty"` 162 163 // WSPathPrefix specifies a path prefix on which ws-rpc is to be served. 164 WSPathPrefix string `toml:",omitempty"` 165 166 // WSOrigins is the list of domain to accept websocket requests from. Please be 167 // aware that the server can only act upon the HTTP request the client sends and 168 // cannot verify the validity of the request header. 169 WSOrigins []string `toml:",omitempty"` 170 171 // WSModules is a list of API modules to expose via the websocket RPC interface. 172 // If the module list is empty, all RPC API endpoints designated public will be 173 // exposed. 174 WSModules []string 175 176 // WSExposeAll exposes all API modules via the WebSocket RPC interface rather 177 // than just the public ones. 178 // 179 // *WARNING* Only set this if the node is running in a trusted network, exposing 180 // private APIs to untrusted users is a major security risk. 181 WSExposeAll bool `toml:",omitempty"` 182 183 // GraphQLCors is the Cross-Origin Resource Sharing header to send to requesting 184 // clients. Please be aware that CORS is a browser enforced security, it's fully 185 // useless for custom HTTP clients. 186 GraphQLCors []string `toml:",omitempty"` 187 188 // GraphQLVirtualHosts is the list of virtual hostnames which are allowed on incoming requests. 189 // This is by default {'localhost'}. Using this prevents attacks like 190 // DNS rebinding, which bypasses SOP by simply masquerading as being within the same 191 // origin. These attacks do not utilize CORS, since they are not cross-domain. 192 // By explicitly checking the Host-header, the server will not allow requests 193 // made against the server with a malicious host domain. 194 // Requests using ip address directly are not affected 195 GraphQLVirtualHosts []string `toml:",omitempty"` 196 197 // Logger is a custom logger to use with the p2p.Server. 198 Logger log.Logger `toml:",omitempty"` 199 200 LogConfig *LogConfig `toml:",omitempty"` 201 202 staticNodesWarning bool 203 trustedNodesWarning bool 204 oldGethResourceWarning bool 205 206 // AllowUnprotectedTxs allows non EIP-155 protected transactions to be send over RPC. 207 AllowUnprotectedTxs bool `toml:",omitempty"` 208 } 209 210 // IPCEndpoint resolves an IPC endpoint based on a configured value, taking into 211 // account the set data folders as well as the designated platform we're currently 212 // running on. 213 func (c *Config) IPCEndpoint() string { 214 // Short circuit if IPC has not been enabled 215 if c.IPCPath == "" { 216 return "" 217 } 218 // On windows we can only use plain top-level pipes 219 if runtime.GOOS == "windows" { 220 if strings.HasPrefix(c.IPCPath, `\\.\pipe\`) { 221 return c.IPCPath 222 } 223 return `\\.\pipe\` + c.IPCPath 224 } 225 // Resolve names into the data directory full paths otherwise 226 if filepath.Base(c.IPCPath) == c.IPCPath { 227 if c.DataDir == "" { 228 return filepath.Join(os.TempDir(), c.IPCPath) 229 } 230 return filepath.Join(c.DataDir, c.IPCPath) 231 } 232 return c.IPCPath 233 } 234 235 // NodeDB returns the path to the discovery node database. 236 func (c *Config) NodeDB() string { 237 if c.DataDir == "" { 238 return "" // ephemeral 239 } 240 return c.ResolvePath(datadirNodeDatabase) 241 } 242 243 // DefaultIPCEndpoint returns the IPC path used by default. 244 func DefaultIPCEndpoint(clientIdentifier string) string { 245 if clientIdentifier == "" { 246 clientIdentifier = strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") 247 if clientIdentifier == "" { 248 panic("empty executable name") 249 } 250 } 251 config := &Config{DataDir: DefaultDataDir(), IPCPath: clientIdentifier + ".ipc"} 252 return config.IPCEndpoint() 253 } 254 255 // HTTPEndpoint resolves an HTTP endpoint based on the configured host interface 256 // and port parameters. 257 func (c *Config) HTTPEndpoint() string { 258 if c.HTTPHost == "" { 259 return "" 260 } 261 return fmt.Sprintf("%s:%d", c.HTTPHost, c.HTTPPort) 262 } 263 264 // DefaultHTTPEndpoint returns the HTTP endpoint used by default. 265 func DefaultHTTPEndpoint() string { 266 config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort} 267 return config.HTTPEndpoint() 268 } 269 270 // WSEndpoint resolves a websocket endpoint based on the configured host interface 271 // and port parameters. 272 func (c *Config) WSEndpoint() string { 273 if c.WSHost == "" { 274 return "" 275 } 276 return fmt.Sprintf("%s:%d", c.WSHost, c.WSPort) 277 } 278 279 // DefaultWSEndpoint returns the websocket endpoint used by default. 280 func DefaultWSEndpoint() string { 281 config := &Config{WSHost: DefaultWSHost, WSPort: DefaultWSPort} 282 return config.WSEndpoint() 283 } 284 285 // ExtRPCEnabled returns the indicator whether node enables the external 286 // RPC(http, ws or graphql). 287 func (c *Config) ExtRPCEnabled() bool { 288 return c.HTTPHost != "" || c.WSHost != "" 289 } 290 291 // NodeName returns the devp2p node identifier. 292 func (c *Config) NodeName() string { 293 name := c.name() 294 // Backwards compatibility: previous versions used title-cased "Geth", keep that. 295 if name == "geth" || name == "geth-testnet" { 296 name = "Geth" 297 } 298 if c.UserIdent != "" { 299 name += "/" + c.UserIdent 300 } 301 if c.Version != "" { 302 name += "/v" + c.Version 303 } 304 name += "/" + runtime.GOOS + "-" + runtime.GOARCH 305 name += "/" + runtime.Version() 306 return name 307 } 308 309 func (c *Config) name() string { 310 if c.Name == "" { 311 progname := strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") 312 if progname == "" { 313 panic("empty executable name, set Config.Name") 314 } 315 return progname 316 } 317 return c.Name 318 } 319 320 // These resources are resolved differently for "geth" instances. 321 var isOldGethResource = map[string]bool{ 322 "chaindata": true, 323 "nodes": true, 324 "nodekey": true, 325 "static-nodes.json": false, // no warning for these because they have their 326 "trusted-nodes.json": false, // own separate warning. 327 } 328 329 // ResolvePath resolves path in the instance directory. 330 func (c *Config) ResolvePath(path string) string { 331 if filepath.IsAbs(path) { 332 return path 333 } 334 if c.DataDir == "" { 335 return "" 336 } 337 // Backwards-compatibility: ensure that data directory files created 338 // by geth 1.4 are used if they exist. 339 if warn, isOld := isOldGethResource[path]; isOld { 340 oldpath := "" 341 if c.name() == "geth" { 342 oldpath = filepath.Join(c.DataDir, path) 343 } 344 if oldpath != "" && common.FileExist(oldpath) { 345 if warn { 346 c.warnOnce(&c.oldGethResourceWarning, "Using deprecated resource file %s, please move this file to the 'geth' subdirectory of datadir.", oldpath) 347 } 348 return oldpath 349 } 350 } 351 return filepath.Join(c.instanceDir(), path) 352 } 353 354 func (c *Config) instanceDir() string { 355 if c.DataDir == "" { 356 return "" 357 } 358 return filepath.Join(c.DataDir, c.name()) 359 } 360 361 // NodeKey retrieves the currently configured private key of the node, checking 362 // first any manually set key, falling back to the one found in the configured 363 // data folder. If no key can be found, a new one is generated. 364 func (c *Config) NodeKey() *ecdsa.PrivateKey { 365 // Use any specifically configured key. 366 if c.P2P.PrivateKey != nil { 367 return c.P2P.PrivateKey 368 } 369 // Generate ephemeral key if no datadir is being used. 370 if c.DataDir == "" { 371 key, err := crypto.GenerateKey() 372 if err != nil { 373 log.Crit(fmt.Sprintf("Failed to generate ephemeral node key: %v", err)) 374 } 375 return key 376 } 377 378 keyfile := c.ResolvePath(datadirPrivateKey) 379 if key, err := crypto.LoadECDSA(keyfile); err == nil { 380 return key 381 } 382 // No persistent key found, generate and store a new one. 383 key, err := crypto.GenerateKey() 384 if err != nil { 385 log.Crit(fmt.Sprintf("Failed to generate node key: %v", err)) 386 } 387 instanceDir := filepath.Join(c.DataDir, c.name()) 388 if err := os.MkdirAll(instanceDir, 0700); err != nil { 389 log.Error(fmt.Sprintf("Failed to persist node key: %v", err)) 390 return key 391 } 392 keyfile = filepath.Join(instanceDir, datadirPrivateKey) 393 if err := crypto.SaveECDSA(keyfile, key); err != nil { 394 log.Error(fmt.Sprintf("Failed to persist node key: %v", err)) 395 } 396 return key 397 } 398 399 // StaticNodes returns a list of node enode URLs configured as static nodes. 400 func (c *Config) StaticNodes() []*enode.Node { 401 return c.parsePersistentNodes(&c.staticNodesWarning, c.ResolvePath(datadirStaticNodes)) 402 } 403 404 // TrustedNodes returns a list of node enode URLs configured as trusted nodes. 405 func (c *Config) TrustedNodes() []*enode.Node { 406 return c.parsePersistentNodes(&c.trustedNodesWarning, c.ResolvePath(datadirTrustedNodes)) 407 } 408 409 // parsePersistentNodes parses a list of discovery node URLs loaded from a .json 410 // file from within the data directory. 411 func (c *Config) parsePersistentNodes(w *bool, path string) []*enode.Node { 412 // Short circuit if no node config is present 413 if c.DataDir == "" { 414 return nil 415 } 416 if _, err := os.Stat(path); err != nil { 417 return nil 418 } 419 c.warnOnce(w, "Found deprecated node list file %s, please use the TOML config file instead.", path) 420 421 // Load the nodes from the config file. 422 var nodelist []string 423 if err := common.LoadJSON(path, &nodelist); err != nil { 424 log.Error(fmt.Sprintf("Can't load node list file: %v", err)) 425 return nil 426 } 427 // Interpret the list as a discovery node array 428 var nodes []*enode.Node 429 for _, url := range nodelist { 430 if url == "" { 431 continue 432 } 433 node, err := enode.Parse(enode.ValidSchemes, url) 434 if err != nil { 435 log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err)) 436 continue 437 } 438 nodes = append(nodes, node) 439 } 440 return nodes 441 } 442 443 // AccountConfig determines the settings for scrypt and keydirectory 444 func (c *Config) AccountConfig() (int, int, string, error) { 445 scryptN := keystore.StandardScryptN 446 scryptP := keystore.StandardScryptP 447 if c.UseLightweightKDF { 448 scryptN = keystore.LightScryptN 449 scryptP = keystore.LightScryptP 450 } 451 452 var ( 453 keydir string 454 err error 455 ) 456 switch { 457 case filepath.IsAbs(c.KeyStoreDir): 458 keydir = c.KeyStoreDir 459 case c.DataDir != "": 460 if c.KeyStoreDir == "" { 461 keydir = filepath.Join(c.DataDir, datadirDefaultKeyStore) 462 } else { 463 keydir, err = filepath.Abs(c.KeyStoreDir) 464 } 465 case c.KeyStoreDir != "": 466 keydir, err = filepath.Abs(c.KeyStoreDir) 467 } 468 return scryptN, scryptP, keydir, err 469 } 470 471 func makeAccountManager(conf *Config) (*accounts.Manager, string, error) { 472 scryptN, scryptP, keydir, err := conf.AccountConfig() 473 var ephemeral string 474 if keydir == "" { 475 // There is no datadir. 476 keydir, err = ioutil.TempDir("", "go-ethereum-keystore") 477 ephemeral = keydir 478 } 479 480 if err != nil { 481 return nil, "", err 482 } 483 if err := os.MkdirAll(keydir, 0700); err != nil { 484 return nil, "", err 485 } 486 // Assemble the account manager and supported backends 487 var backends []accounts.Backend 488 if len(conf.ExternalSigner) > 0 { 489 log.Info("Using external signer", "url", conf.ExternalSigner) 490 if extapi, err := external.NewExternalBackend(conf.ExternalSigner); err == nil { 491 backends = append(backends, extapi) 492 } else { 493 return nil, "", fmt.Errorf("error connecting to external signer: %v", err) 494 } 495 } 496 if len(backends) == 0 { 497 // For now, we're using EITHER external signer OR local signers. 498 // If/when we implement some form of lockfile for USB and keystore wallets, 499 // we can have both, but it's very confusing for the user to see the same 500 // accounts in both externally and locally, plus very racey. 501 backends = append(backends, keystore.NewKeyStore(keydir, scryptN, scryptP)) 502 if conf.USB { 503 // Start a USB hub for Ledger hardware wallets 504 if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil { 505 log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err)) 506 } else { 507 backends = append(backends, ledgerhub) 508 } 509 // Start a USB hub for Trezor hardware wallets (HID version) 510 if trezorhub, err := usbwallet.NewTrezorHubWithHID(); err != nil { 511 log.Warn(fmt.Sprintf("Failed to start HID Trezor hub, disabling: %v", err)) 512 } else { 513 backends = append(backends, trezorhub) 514 } 515 // Start a USB hub for Trezor hardware wallets (WebUSB version) 516 if trezorhub, err := usbwallet.NewTrezorHubWithWebUSB(); err != nil { 517 log.Warn(fmt.Sprintf("Failed to start WebUSB Trezor hub, disabling: %v", err)) 518 } else { 519 backends = append(backends, trezorhub) 520 } 521 } 522 if len(conf.SmartCardDaemonPath) > 0 { 523 // Start a smart card hub 524 if schub, err := scwallet.NewHub(conf.SmartCardDaemonPath, scwallet.Scheme, keydir); err != nil { 525 log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err)) 526 } else { 527 backends = append(backends, schub) 528 } 529 } 530 } 531 532 return accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: conf.InsecureUnlockAllowed}, backends...), ephemeral, nil 533 } 534 535 var warnLock sync.Mutex 536 537 func (c *Config) warnOnce(w *bool, format string, args ...interface{}) { 538 warnLock.Lock() 539 defer warnLock.Unlock() 540 541 if *w { 542 return 543 } 544 l := c.Logger 545 if l == nil { 546 l = log.Root() 547 } 548 l.Warn(fmt.Sprintf(format, args...)) 549 *w = true 550 } 551 552 type LogConfig struct { 553 FileRoot string 554 FilePath string 555 MaxBytesSize uint 556 Level string 557 }