package params import ( "encoding/json" "errors" "fmt" "io/ioutil" "os" "path/filepath" "strings" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/log" ) // default node configuration options var ( UseMainnetFlag = "false" // to be overridden via -ldflags '-X geth/params.UseMainnetFlag' UseMainnet = false ) func init() { if UseMainnetFlag == "true" { // set at compile time, here we make sure to set corresponding boolean flag UseMainnet = true } } var ( ErrMissingDataDir = errors.New("missing required 'DataDir' parameter") ErrMissingNetworkId = errors.New("missing required 'NetworkId' parameter") ) // LightEthConfig holds LES-related configuration // Status nodes are always lightweight clients (due to mobile platform constraints) type LightEthConfig struct { // Enabled flag specifies whether protocol is enabled Enabled bool // Genesis is JSON to seed the chain database with Genesis string // DatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced) DatabaseCache int } // WhisperConfig holds SHH-related configuration type WhisperConfig struct { // Enabled flag specifies whether protocol is enabled Enabled bool // EchoMode if mode is on, prints some arguments for diagnostics EchoMode bool // BootstrapNode whether node doesn't actively connect to peers, and waits for incoming connections BootstrapNode bool // ForwarderNode is mode when node only forwards messages, neither sends nor decrypts messages ForwarderNode bool // MailServerNode is mode when node is capable of delivering expired messages on demand MailServerNode bool // MailServerPassword is password for MailServer's symmetric key MailServerPassword string // NotificationServerNode is mode when node is capable of sending Push (and probably other kinds) Notifications NotificationServerNode bool // NotificationServerPassword is password for NotificationServer's symmetric key (used in discovery) NotificationServerPassword string // DataDir is the file system folder Whisper should use for any data storage needs. DataDir string // Port Whisper node's listening port Port int // MinimumPoW minimum PoW for Whisper messages MinimumPoW float64 // TTL time to live for messages, in seconds TTL int } // SwarmConfig holds Swarm-related configuration type SwarmConfig struct { // Enabled flag specifies whether protocol is enabled Enabled bool } // NodeConfig stores configuration options for a node type NodeConfig struct { // TestNet flag whether given configuration describes a test or mainnet TestNet bool // NetworkId sets network to use for selecting peers to connect to NetworkId uint64 // DataDir is the file system folder the node should use for any data storage needs. DataDir string // KeyStoreDir is the file system folder that contains private keys. // If KeyStoreDir is empty, the default location is the "keystore" subdirectory of DataDir. KeyStoreDir string // PrivateKeyFile is a filename with node ID (private key) // This file should contain a valid secp256k1 private key that will be used for both // remote peer identification as well as network traffic encryption. NodeKeyFile string // Name sets the instance name of the node. It must not contain the / character. Name string // Version exposes program's version. It is used in the devp2p node identifier. Version string // APIModules is a comma-separated list of API modules exposed via *any* (HTTP/WS/IPC) RPC interface. APIModules string // HTTPHost is the host interface on which to start the HTTP RPC server. // Pass empty string if no HTTP RPC interface needs to be started. HTTPHost string // HTTPPort is the TCP port number on which to start the Geth's HTTP RPC server. HTTPPort int // WSHost is a host interface for the WebSocket RPC server WSHost string // WSPort is the TCP port number on which to start the Geth's WebSocket RPC server. WSPort int // WSEnabled specifies whether WS-RPC Server is enabled or not WSEnabled bool // IPCFile is filename of exposed IPC RPC Server IPCFile string // IPCEnabled specifies whether IPC-RPC Server is enabled or not IPCEnabled bool // TLSEnabled specifies whether TLS support should be enabled on node or not // TLS support is only planned in go-ethereum, so we are using our own patch. TLSEnabled bool // MaxPeers is the maximum number of (global) peers that can be connected. // Set to zero, if only static or trusted peers are allowed to connect. MaxPeers int // MaxPendingPeers is the maximum number of peers that can be pending in the // handshake phase, counted separately for inbound and outbound connections. MaxPendingPeers int // LogToFile specified whether logs should be saved into file LogEnabled bool // LogFile is filename where exposed logs get written to LogFile string // LogLevel defines minimum log level. Valid names are "ERROR", "WARNING", "INFO", "DEBUG", and "TRACE". LogLevel string // LogToStderr defines whether logged info should also be output to os.Stderr LogToStderr bool // LightEthConfig extra configuration for LES LightEthConfig *LightEthConfig `json:"LightEthConfig,"` // WhisperConfig extra configuration for SHH WhisperConfig *WhisperConfig `json:"WhisperConfig,"` // SwarmConfig extra configuration for Swarm and ENS SwarmConfig *SwarmConfig `json:"SwarmConfig,"` } // NewNodeConfig creates new node configuration object func NewNodeConfig(dataDir string, networkId uint64) (*NodeConfig, error) { nodeConfig := &NodeConfig{ NetworkId: networkId, DataDir: dataDir, Name: ClientIdentifier, Version: Version, HTTPHost: HTTPHost, HTTPPort: HTTPPort, APIModules: APIModules, WSHost: WSHost, WSPort: WSPort, MaxPeers: MaxPeers, MaxPendingPeers: MaxPendingPeers, IPCFile: IPCFile, LogFile: LogFile, LogLevel: LogLevel, LogToStderr: LogToStderr, LightEthConfig: &LightEthConfig{ Enabled: true, DatabaseCache: DatabaseCache, }, WhisperConfig: &WhisperConfig{ Enabled: true, Port: WhisperPort, MinimumPoW: WhisperMinimumPoW, TTL: WhisperTTL, }, SwarmConfig: &SwarmConfig{}, } // auto-populate some dependent values if err := nodeConfig.populateGenesis(); err != nil { return nil, err } if err := nodeConfig.populateDirs(); err != nil { return nil, err } return nodeConfig, nil } // populateDirs updates directories that should be wrt to DataDir func (c *NodeConfig) populateDirs() error { makeSubDirPath := func(baseDir, subDir string) string { if len(baseDir) == 0 { return "" } return filepath.Join(baseDir, subDir) } if len(c.KeyStoreDir) == 0 { c.KeyStoreDir = makeSubDirPath(c.DataDir, KeyStoreDir) } if len(c.WhisperConfig.DataDir) == 0 { c.WhisperConfig.DataDir = makeSubDirPath(c.DataDir, WhisperDataDir) } return nil } // populateChainConfig does necessary adjustments to config object (depending on network node will be runnin on) func (c *NodeConfig) populateGenesis() error { c.TestNet = false if c.NetworkId == TestNetworkId { c.TestNet = true } var genesis *core.Genesis if c.TestNet { genesis = core.DefaultTestnetGenesisBlock() } else { genesis = core.DefaultGenesisBlock() } // encode the genesis into JSON enc, err := json.Marshal(genesis) if err != nil { return err } c.LightEthConfig.Genesis = string(enc) return nil } // LoadNodeConfig parses incoming JSON and returned it as Config func LoadNodeConfig(configJSON string) (*NodeConfig, error) { nodeConfig, err := NewNodeConfig("", 0) if err != nil { return nil, err } decoder := json.NewDecoder(strings.NewReader(configJSON)) //decoder.UseNumber() // override default configuration with values by JSON input if err := decoder.Decode(&nodeConfig); err != nil { return nil, err } // repopulate if err := nodeConfig.populateGenesis(); err != nil { return nil, err } if err := nodeConfig.populateDirs(); err != nil { return nil, err } if len(nodeConfig.DataDir) == 0 { return nil, ErrMissingDataDir } if nodeConfig.NetworkId <= 0 { return nil, ErrMissingNetworkId } return nodeConfig, nil } // Save dumps configuration to the disk func (c *NodeConfig) Save() error { data, err := json.MarshalIndent(c, "", " ") if err != nil { return err } if err := os.MkdirAll(c.DataDir, os.ModePerm); err != nil { return err } configFilePath := filepath.Join(c.DataDir, "config.json") if err := ioutil.WriteFile(configFilePath, data, os.ModePerm); err != nil { return err } log.Info(fmt.Sprintf("config file saved: %v", configFilePath)) return nil } // String dumps config object as nicely indented JSON func (c *NodeConfig) String() string { data, _ := json.MarshalIndent(c, "", " ") return string(data) } // String dumps config object as nicely indented JSON func (c *WhisperConfig) String() string { data, _ := json.MarshalIndent(c, "", " ") return string(data) } // String dumps config object as nicely indented JSON func (c *SwarmConfig) String() string { data, _ := json.MarshalIndent(c, "", " ") return string(data) }