| 
									
										
										
										
											2016-04-14 18:18:24 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"crypto/ecdsa" | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	"runtime" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/accounts" | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/accounts/keystore" | 
					
						
							| 
									
										
										
										
											2017-01-23 09:58:05 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/accounts/usbwallet" | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p/discover" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-06 19:43:43 +03:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	datadirPrivateKey      = "nodekey"            // Path within the datadir to the node's private key | 
					
						
							|  |  |  | 	datadirDefaultKeyStore = "keystore"           // Path within the datadir to the keystore | 
					
						
							|  |  |  | 	datadirStaticNodes     = "static-nodes.json"  // Path within the datadir to the static node list | 
					
						
							|  |  |  | 	datadirTrustedNodes    = "trusted-nodes.json" // Path within the datadir to the trusted node list | 
					
						
							|  |  |  | 	datadirNodeDatabase    = "nodes"              // Path within the datadir to store the node infos | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Config represents a small collection of configuration values to fine tune the | 
					
						
							|  |  |  | // P2P network layer of a protocol stack. These values can be further extended by | 
					
						
							|  |  |  | // all registered services. | 
					
						
							|  |  |  | type Config struct { | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	// Name sets the instance name of the node. It must not contain the / character and is | 
					
						
							|  |  |  | 	// used in the devp2p node identifier. The instance name of geth is "geth". If no | 
					
						
							|  |  |  | 	// value is specified, the basename of the current executable is used. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	Name string `toml:"-"` | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// UserIdent, if set, is used as an additional component in the devp2p node identifier. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	UserIdent string `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Version should be set to the version number of the program. It is used | 
					
						
							|  |  |  | 	// in the devp2p node identifier. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	Version string `toml:"-"` | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	// DataDir is the file system folder the node should use for any data storage | 
					
						
							|  |  |  | 	// requirements. The configured data directory will not be directly shared with | 
					
						
							|  |  |  | 	// registered services, instead those can use utility methods to create/access | 
					
						
							|  |  |  | 	// databases or flat files. This enables ephemeral nodes which can fully reside | 
					
						
							|  |  |  | 	// in memory. | 
					
						
							|  |  |  | 	DataDir string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	// Configuration of peer-to-peer networking. | 
					
						
							|  |  |  | 	P2P p2p.Config | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	// KeyStoreDir is the file system folder that contains private keys. The directory can | 
					
						
							|  |  |  | 	// be specified as a relative path, in which case it is resolved relative to the | 
					
						
							|  |  |  | 	// current directory. | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// If KeyStoreDir is empty, the default location is the "keystore" subdirectory of | 
					
						
							|  |  |  | 	// DataDir. If DataDir is unspecified and KeyStoreDir is empty, an ephemeral directory | 
					
						
							|  |  |  | 	// is created by New and destroyed when the node is stopped. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	KeyStoreDir string `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// UseLightweightKDF lowers the memory and CPU requirements of the key store | 
					
						
							|  |  |  | 	// scrypt KDF at the expense of security. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	UseLightweightKDF bool `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-20 14:01:51 +03:00
										 |  |  | 	// NoUSB disables hardware wallet monitoring and connectivity. | 
					
						
							|  |  |  | 	NoUSB bool `toml:",omitempty"` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	// IPCPath is the requested location to place the IPC endpoint. If the path is | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	// a simple file name, it is placed inside the data directory (or on the root | 
					
						
							|  |  |  | 	// pipe path on Windows), whereas if it's a resolvable path name (absolute or | 
					
						
							|  |  |  | 	// relative), then that specific path is enforced. An empty path disables IPC. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	IPCPath string `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	// HTTPHost is the host interface on which to start the HTTP RPC server. If this | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	// field is empty, no HTTP API endpoint will be started. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	HTTPHost string `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	// HTTPPort is the TCP port number on which to start the HTTP RPC server. The | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	// default zero value is/ valid and will pick a port number randomly (useful | 
					
						
							|  |  |  | 	// for ephemeral nodes). | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	HTTPPort int `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	// HTTPCors is the Cross-Origin Resource Sharing header to send to requesting | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	// clients. Please be aware that CORS is a browser enforced security, it's fully | 
					
						
							|  |  |  | 	// useless for custom HTTP clients. | 
					
						
							| 
									
										
										
										
											2017-04-12 23:04:14 +02:00
										 |  |  | 	HTTPCors []string `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-12 13:52:07 +01:00
										 |  |  | 	// HTTPVirtualHosts is the list of virtual hostnames which are allowed on incoming requests. | 
					
						
							|  |  |  | 	// This is by default {'localhost'}. Using this prevents attacks like | 
					
						
							|  |  |  | 	// DNS rebinding, which bypasses SOP by simply masquerading as being within the same | 
					
						
							|  |  |  | 	// origin. These attacks do not utilize CORS, since they are not cross-domain. | 
					
						
							|  |  |  | 	// By explicitly checking the Host-header, the server will not allow requests | 
					
						
							|  |  |  | 	// made against the server with a malicious host domain. | 
					
						
							|  |  |  | 	// Requests using ip address directly are not affected | 
					
						
							|  |  |  | 	HTTPVirtualHosts []string `toml:",omitempty"` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	// HTTPModules is a list of API modules to expose via the HTTP RPC interface. | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	// If the module list is empty, all RPC API endpoints designated public will be | 
					
						
							|  |  |  | 	// exposed. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	HTTPModules []string `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	// WSHost is the host interface on which to start the websocket RPC server. If | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 	// this field is empty, no websocket API endpoint will be started. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	WSHost string `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	// WSPort is the TCP port number on which to start the websocket RPC server. The | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 	// default zero value is/ valid and will pick a port number randomly (useful for | 
					
						
							|  |  |  | 	// ephemeral nodes). | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	WSPort int `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-14 09:38:54 +01:00
										 |  |  | 	// WSOrigins is the list of domain to accept websocket requests from. Please be | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	// aware that the server can only act upon the HTTP request the client sends and | 
					
						
							|  |  |  | 	// cannot verify the validity of the request header. | 
					
						
							| 
									
										
										
										
											2017-04-12 23:04:14 +02:00
										 |  |  | 	WSOrigins []string `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	// WSModules is a list of API modules to expose via the websocket RPC interface. | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 	// If the module list is empty, all RPC API endpoints designated public will be | 
					
						
							|  |  |  | 	// exposed. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	WSModules []string `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// WSExposeAll exposes all API modules via the WebSocket RPC interface rather | 
					
						
							|  |  |  | 	// than just the public ones. | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// *WARNING* Only set this if the node is running in a trusted network, exposing | 
					
						
							|  |  |  | 	// private APIs to untrusted users is a major security risk. | 
					
						
							|  |  |  | 	WSExposeAll bool `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2017-12-01 11:49:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Logger is a custom logger to use with the p2p.Server. | 
					
						
							| 
									
										
										
										
											2018-02-12 13:52:07 +01:00
										 |  |  | 	Logger log.Logger `toml:",omitempty"` | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | // IPCEndpoint resolves an IPC endpoint based on a configured value, taking into | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | // account the set data folders as well as the designated platform we're currently | 
					
						
							|  |  |  | // running on. | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | func (c *Config) IPCEndpoint() string { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	// Short circuit if IPC has not been enabled | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	if c.IPCPath == "" { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// On windows we can only use plain top-level pipes | 
					
						
							|  |  |  | 	if runtime.GOOS == "windows" { | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 		if strings.HasPrefix(c.IPCPath, `\\.\pipe\`) { | 
					
						
							|  |  |  | 			return c.IPCPath | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 		return `\\.\pipe\` + c.IPCPath | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Resolve names into the data directory full paths otherwise | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	if filepath.Base(c.IPCPath) == c.IPCPath { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 		if c.DataDir == "" { | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 			return filepath.Join(os.TempDir(), c.IPCPath) | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 		return filepath.Join(c.DataDir, c.IPCPath) | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	return c.IPCPath | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | // NodeDB returns the path to the discovery node database. | 
					
						
							|  |  |  | func (c *Config) NodeDB() string { | 
					
						
							|  |  |  | 	if c.DataDir == "" { | 
					
						
							|  |  |  | 		return "" // ephemeral | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-06 19:43:43 +03:00
										 |  |  | 	return c.resolvePath(datadirNodeDatabase) | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | // DefaultIPCEndpoint returns the IPC path used by default. | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | func DefaultIPCEndpoint(clientIdentifier string) string { | 
					
						
							|  |  |  | 	if clientIdentifier == "" { | 
					
						
							|  |  |  | 		clientIdentifier = strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") | 
					
						
							|  |  |  | 		if clientIdentifier == "" { | 
					
						
							|  |  |  | 			panic("empty executable name") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-16 11:53:50 +02:00
										 |  |  | 	config := &Config{DataDir: DefaultDataDir(), IPCPath: clientIdentifier + ".ipc"} | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	return config.IPCEndpoint() | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | // HTTPEndpoint resolves an HTTP endpoint based on the configured host interface | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | // and port parameters. | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | func (c *Config) HTTPEndpoint() string { | 
					
						
							|  |  |  | 	if c.HTTPHost == "" { | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	return fmt.Sprintf("%s:%d", c.HTTPHost, c.HTTPPort) | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | // DefaultHTTPEndpoint returns the HTTP endpoint used by default. | 
					
						
							|  |  |  | func DefaultHTTPEndpoint() string { | 
					
						
							| 
									
										
										
										
											2016-09-16 11:53:50 +02:00
										 |  |  | 	config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort} | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	return config.HTTPEndpoint() | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | // WSEndpoint resolves an websocket endpoint based on the configured host interface | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | // and port parameters. | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | func (c *Config) WSEndpoint() string { | 
					
						
							|  |  |  | 	if c.WSHost == "" { | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	return fmt.Sprintf("%s:%d", c.WSHost, c.WSPort) | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | // DefaultWSEndpoint returns the websocket endpoint used by default. | 
					
						
							|  |  |  | func DefaultWSEndpoint() string { | 
					
						
							| 
									
										
										
										
											2016-09-16 11:53:50 +02:00
										 |  |  | 	config := &Config{WSHost: DefaultWSHost, WSPort: DefaultWSPort} | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | 	return config.WSEndpoint() | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | // NodeName returns the devp2p node identifier. | 
					
						
							|  |  |  | func (c *Config) NodeName() string { | 
					
						
							|  |  |  | 	name := c.name() | 
					
						
							|  |  |  | 	// Backwards compatibility: previous versions used title-cased "Geth", keep that. | 
					
						
							|  |  |  | 	if name == "geth" || name == "geth-testnet" { | 
					
						
							|  |  |  | 		name = "Geth" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if c.UserIdent != "" { | 
					
						
							|  |  |  | 		name += "/" + c.UserIdent | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if c.Version != "" { | 
					
						
							|  |  |  | 		name += "/v" + c.Version | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-05 22:51:01 +03:00
										 |  |  | 	name += "/" + runtime.GOOS + "-" + runtime.GOARCH | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	name += "/" + runtime.Version() | 
					
						
							|  |  |  | 	return name | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *Config) name() string { | 
					
						
							|  |  |  | 	if c.Name == "" { | 
					
						
							|  |  |  | 		progname := strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") | 
					
						
							|  |  |  | 		if progname == "" { | 
					
						
							|  |  |  | 			panic("empty executable name, set Config.Name") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return progname | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return c.Name | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-10 17:03:24 +01:00
										 |  |  | // These resources are resolved differently for "geth" instances. | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | var isOldGethResource = map[string]bool{ | 
					
						
							|  |  |  | 	"chaindata":          true, | 
					
						
							|  |  |  | 	"nodes":              true, | 
					
						
							|  |  |  | 	"nodekey":            true, | 
					
						
							|  |  |  | 	"static-nodes.json":  true, | 
					
						
							|  |  |  | 	"trusted-nodes.json": true, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // resolvePath resolves path in the instance directory. | 
					
						
							|  |  |  | func (c *Config) resolvePath(path string) string { | 
					
						
							|  |  |  | 	if filepath.IsAbs(path) { | 
					
						
							|  |  |  | 		return path | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if c.DataDir == "" { | 
					
						
							|  |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Backwards-compatibility: ensure that data directory files created | 
					
						
							|  |  |  | 	// by geth 1.4 are used if they exist. | 
					
						
							|  |  |  | 	if c.name() == "geth" && isOldGethResource[path] { | 
					
						
							|  |  |  | 		oldpath := "" | 
					
						
							|  |  |  | 		if c.Name == "geth" { | 
					
						
							|  |  |  | 			oldpath = filepath.Join(c.DataDir, path) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if oldpath != "" && common.FileExist(oldpath) { | 
					
						
							|  |  |  | 			// TODO: print warning | 
					
						
							|  |  |  | 			return oldpath | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-10 17:03:24 +01:00
										 |  |  | 	return filepath.Join(c.instanceDir(), path) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *Config) instanceDir() string { | 
					
						
							|  |  |  | 	if c.DataDir == "" { | 
					
						
							|  |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return filepath.Join(c.DataDir, c.name()) | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // NodeKey retrieves the currently configured private key of the node, checking | 
					
						
							|  |  |  | // first any manually set key, falling back to the one found in the configured | 
					
						
							|  |  |  | // data folder. If no key can be found, a new one is generated. | 
					
						
							|  |  |  | func (c *Config) NodeKey() *ecdsa.PrivateKey { | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	// Use any specifically configured key. | 
					
						
							| 
									
										
										
										
											2017-04-12 16:27:23 +02:00
										 |  |  | 	if c.P2P.PrivateKey != nil { | 
					
						
							|  |  |  | 		return c.P2P.PrivateKey | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	// Generate ephemeral key if no datadir is being used. | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if c.DataDir == "" { | 
					
						
							|  |  |  | 		key, err := crypto.GenerateKey() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 			log.Crit(fmt.Sprintf("Failed to generate ephemeral node key: %v", err)) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return key | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	keyfile := c.resolvePath(datadirPrivateKey) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if key, err := crypto.LoadECDSA(keyfile); err == nil { | 
					
						
							|  |  |  | 		return key | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	// No persistent key found, generate and store a new one. | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	key, err := crypto.GenerateKey() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 		log.Crit(fmt.Sprintf("Failed to generate node key: %v", err)) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	instanceDir := filepath.Join(c.DataDir, c.name()) | 
					
						
							|  |  |  | 	if err := os.MkdirAll(instanceDir, 0700); err != nil { | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 		log.Error(fmt.Sprintf("Failed to persist node key: %v", err)) | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 		return key | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	keyfile = filepath.Join(instanceDir, datadirPrivateKey) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if err := crypto.SaveECDSA(keyfile, key); err != nil { | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 		log.Error(fmt.Sprintf("Failed to persist node key: %v", err)) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return key | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StaticNodes returns a list of node enode URLs configured as static nodes. | 
					
						
							|  |  |  | func (c *Config) StaticNodes() []*discover.Node { | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	return c.parsePersistentNodes(c.resolvePath(datadirStaticNodes)) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-18 03:58:46 -05:00
										 |  |  | // TrustedNodes returns a list of node enode URLs configured as trusted nodes. | 
					
						
							|  |  |  | func (c *Config) TrustedNodes() []*discover.Node { | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	return c.parsePersistentNodes(c.resolvePath(datadirTrustedNodes)) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // parsePersistentNodes parses a list of discovery node URLs loaded from a .json | 
					
						
							|  |  |  | // file from within the data directory. | 
					
						
							| 
									
										
										
										
											2016-11-18 19:45:06 +08:00
										 |  |  | func (c *Config) parsePersistentNodes(path string) []*discover.Node { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	// Short circuit if no node config is present | 
					
						
							|  |  |  | 	if c.DataDir == "" { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := os.Stat(path); err != nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	// Load the nodes from the config file. | 
					
						
							|  |  |  | 	var nodelist []string | 
					
						
							|  |  |  | 	if err := common.LoadJSON(path, &nodelist); err != nil { | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 		log.Error(fmt.Sprintf("Can't load node file %s: %v", path, err)) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Interpret the list as a discovery node array | 
					
						
							|  |  |  | 	var nodes []*discover.Node | 
					
						
							|  |  |  | 	for _, url := range nodelist { | 
					
						
							|  |  |  | 		if url == "" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		node, err := discover.ParseNode(url) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 			log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err)) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		nodes = append(nodes, node) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nodes | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 17:39:53 +01:00
										 |  |  | // AccountConfig determines the settings for scrypt and keydirectory | 
					
						
							|  |  |  | func (c *Config) AccountConfig() (int, int, string, error) { | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 	scryptN := keystore.StandardScryptN | 
					
						
							|  |  |  | 	scryptP := keystore.StandardScryptP | 
					
						
							| 
									
										
										
										
											2017-11-20 17:39:53 +01:00
										 |  |  | 	if c.UseLightweightKDF { | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 		scryptN = keystore.LightScryptN | 
					
						
							|  |  |  | 		scryptP = keystore.LightScryptP | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2017-11-20 17:39:53 +01:00
										 |  |  | 		keydir string | 
					
						
							|  |  |  | 		err    error | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	switch { | 
					
						
							| 
									
										
										
										
											2017-11-20 17:39:53 +01:00
										 |  |  | 	case filepath.IsAbs(c.KeyStoreDir): | 
					
						
							|  |  |  | 		keydir = c.KeyStoreDir | 
					
						
							|  |  |  | 	case c.DataDir != "": | 
					
						
							|  |  |  | 		if c.KeyStoreDir == "" { | 
					
						
							|  |  |  | 			keydir = filepath.Join(c.DataDir, datadirDefaultKeyStore) | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2017-11-20 17:39:53 +01:00
										 |  |  | 			keydir, err = filepath.Abs(c.KeyStoreDir) | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-11-20 17:39:53 +01:00
										 |  |  | 	case c.KeyStoreDir != "": | 
					
						
							|  |  |  | 		keydir, err = filepath.Abs(c.KeyStoreDir) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return scryptN, scryptP, keydir, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func makeAccountManager(conf *Config) (*accounts.Manager, string, error) { | 
					
						
							|  |  |  | 	scryptN, scryptP, keydir, err := conf.AccountConfig() | 
					
						
							|  |  |  | 	var ephemeral string | 
					
						
							|  |  |  | 	if keydir == "" { | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 		// There is no datadir. | 
					
						
							|  |  |  | 		keydir, err = ioutil.TempDir("", "go-ethereum-keystore") | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 		ephemeral = keydir | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-20 17:39:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, "", err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := os.MkdirAll(keydir, 0700); err != nil { | 
					
						
							|  |  |  | 		return nil, "", err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-23 09:58:05 +02:00
										 |  |  | 	// Assemble the account manager and supported backends | 
					
						
							|  |  |  | 	backends := []accounts.Backend{ | 
					
						
							|  |  |  | 		keystore.NewKeyStore(keydir, scryptN, scryptP), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-20 14:01:51 +03:00
										 |  |  | 	if !conf.NoUSB { | 
					
						
							| 
									
										
										
										
											2017-08-01 17:45:17 +02:00
										 |  |  | 		// Start a USB hub for Ledger hardware wallets | 
					
						
							| 
									
										
										
										
											2017-04-20 14:01:51 +03:00
										 |  |  | 		if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil { | 
					
						
							|  |  |  | 			log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err)) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			backends = append(backends, ledgerhub) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-01 17:45:17 +02:00
										 |  |  | 		// Start a USB hub for Trezor hardware wallets | 
					
						
							|  |  |  | 		if trezorhub, err := usbwallet.NewTrezorHub(); err != nil { | 
					
						
							|  |  |  | 			log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err)) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			backends = append(backends, trezorhub) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-23 09:58:05 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-08 20:25:52 +02:00
										 |  |  | 	return accounts.NewManager(backends...), ephemeral, nil | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | } |