flags.go 32.7 KB
Newer Older
F
Felix Lange 已提交
1 2 3 4 5 6 7 8 9 10
// Copyright 2015 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
F
Felix Lange 已提交
12 13 14
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
15
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
F
Felix Lange 已提交
16

17
// Package utils contains internal helper functions for go-ethereum commands.
18 19 20 21
package utils

import (
	"crypto/ecdsa"
22
	"fmt"
23
	"io/ioutil"
24
	"math/big"
25
	"os"
26
	"path/filepath"
27
	"runtime"
28
	"strconv"
29
	"strings"
30

F
Felix Lange 已提交
31
	"github.com/ethereum/go-ethereum/accounts"
32
	"github.com/ethereum/go-ethereum/accounts/keystore"
Z
zelig 已提交
33
	"github.com/ethereum/go-ethereum/common"
34
	"github.com/ethereum/go-ethereum/consensus/ethash"
35
	"github.com/ethereum/go-ethereum/core"
36
	"github.com/ethereum/go-ethereum/core/state"
37
	"github.com/ethereum/go-ethereum/core/vm"
38 39
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/eth"
40 41
	"github.com/ethereum/go-ethereum/eth/downloader"
	"github.com/ethereum/go-ethereum/eth/gasprice"
42
	"github.com/ethereum/go-ethereum/ethdb"
43
	"github.com/ethereum/go-ethereum/ethstats"
44
	"github.com/ethereum/go-ethereum/event"
45
	"github.com/ethereum/go-ethereum/les"
46
	"github.com/ethereum/go-ethereum/log"
B
Bas van Kervel 已提交
47
	"github.com/ethereum/go-ethereum/metrics"
48
	"github.com/ethereum/go-ethereum/node"
49
	"github.com/ethereum/go-ethereum/p2p"
50
	"github.com/ethereum/go-ethereum/p2p/discover"
51
	"github.com/ethereum/go-ethereum/p2p/discv5"
52
	"github.com/ethereum/go-ethereum/p2p/nat"
53
	"github.com/ethereum/go-ethereum/p2p/netutil"
54
	"github.com/ethereum/go-ethereum/params"
55
	whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
56
	"gopkg.in/urfave/cli.v1"
57 58
)

59 60 61 62 63 64 65 66 67 68 69 70 71
var (
	CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} [arguments...]
{{if .cmd.Description}}{{.cmd.Description}}
{{end}}{{if .cmd.Subcommands}}
SUBCOMMANDS:
	{{range .cmd.Subcommands}}{{.cmd.Name}}{{with .cmd.ShortName}}, {{.cmd}}{{end}}{{ "\t" }}{{.cmd.Usage}}
	{{end}}{{end}}{{if .categorizedFlags}}
{{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS:
{{range $categorized.Flags}}{{"\t"}}{{.}}
{{end}}
{{end}}{{end}}`
)

72 73 74 75 76 77 78 79 80 81 82 83 84 85
func init() {
	cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]

VERSION:
   {{.Version}}

COMMANDS:
   {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
   {{end}}{{if .Flags}}
GLOBAL OPTIONS:
   {{range .Flags}}{{.}}
   {{end}}{{end}}
`

86
	cli.CommandHelpTemplate = CommandHelpTemplate
87 88
}

F
Felix Lange 已提交
89
// NewApp creates an app with sane defaults.
90
func NewApp(gitCommit, usage string) *cli.App {
F
Felix Lange 已提交
91
	app := cli.NewApp()
92
	app.Name = filepath.Base(os.Args[0])
F
Felix Lange 已提交
93
	app.Author = ""
O
obscuren 已提交
94
	//app.Authors = nil
F
Felix Lange 已提交
95
	app.Email = ""
96
	app.Version = params.Version
97 98 99
	if gitCommit != "" {
		app.Version += "-" + gitCommit[:8]
	}
F
Felix Lange 已提交
100 101 102 103
	app.Usage = usage
	return app
}

104 105 106 107 108 109 110 111 112
// These are all the command line flags we support.
// If you add to this list, please remember to include the
// flag in the appropriate command definition.
//
// The flags are defined here so their names and help texts
// are the same for all commands.

var (
	// General settings
113
	DataDirFlag = DirectoryFlag{
114
		Name:  "datadir",
115
		Usage: "Data directory for the databases and keystore",
116
		Value: DirectoryString{node.DefaultDataDir()},
117
	}
K
Kobi Gurkan 已提交
118 119 120 121
	KeyStoreDirFlag = DirectoryFlag{
		Name:  "keystore",
		Usage: "Directory for the keystore (default = inside the datadir)",
	}
122 123 124 125
	NoUSBFlag = cli.BoolFlag{
		Name:  "nousb",
		Usage: "Disables monitoring for and managine USB hardware wallets",
	}
126 127 128 129 130 131 132
	EthashCacheDirFlag = DirectoryFlag{
		Name:  "ethash.cachedir",
		Usage: "Directory to store the ethash verification caches (default = inside the datadir)",
	}
	EthashCachesInMemoryFlag = cli.IntFlag{
		Name:  "ethash.cachesinmem",
		Usage: "Number of recent ethash caches to keep in memory (16MB each)",
133
		Value: eth.DefaultConfig.EthashCachesInMem,
134 135 136 137
	}
	EthashCachesOnDiskFlag = cli.IntFlag{
		Name:  "ethash.cachesondisk",
		Usage: "Number of recent ethash caches to keep on disk (16MB each)",
138
		Value: eth.DefaultConfig.EthashCachesOnDisk,
139 140 141 142
	}
	EthashDatasetDirFlag = DirectoryFlag{
		Name:  "ethash.dagdir",
		Usage: "Directory to store the ethash mining DAGs (default = inside home folder)",
143
		Value: DirectoryString{eth.DefaultConfig.EthashDatasetDir},
144
	}
145 146 147
	EthashDatasetsInMemoryFlag = cli.IntFlag{
		Name:  "ethash.dagsinmem",
		Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
148
		Value: eth.DefaultConfig.EthashDatasetsInMem,
149
	}
150 151
	EthashDatasetsOnDiskFlag = cli.IntFlag{
		Name:  "ethash.dagsondisk",
152
		Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
153
		Value: eth.DefaultConfig.EthashDatasetsOnDisk,
154
	}
155
	NetworkIdFlag = cli.Uint64Flag{
Z
zelig 已提交
156
		Name:  "networkid",
157
		Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)",
158
		Value: eth.DefaultConfig.NetworkId,
Z
zelig 已提交
159
	}
160
	TestnetFlag = cli.BoolFlag{
161
		Name:  "testnet",
162
		Usage: "Ropsten network: pre-configured proof-of-work test network",
163
	}
164 165 166 167
	RinkebyFlag = cli.BoolFlag{
		Name:  "rinkeby",
		Usage: "Rinkeby network: pre-configured proof-of-authority test network",
	}
168 169
	DevModeFlag = cli.BoolFlag{
		Name:  "dev",
170
		Usage: "Developer mode: pre-configured private network with several debugging flags",
171
	}
172 173
	IdentityFlag = cli.StringFlag{
		Name:  "identity",
174
		Usage: "Custom node name",
175
	}
Z
zelig 已提交
176 177 178
	DocRootFlag = DirectoryFlag{
		Name:  "docroot",
		Usage: "Document Root for HTTPClient file scheme",
179
		Value: DirectoryString{homeDir()},
Z
zelig 已提交
180
	}
181 182
	FastSyncFlag = cli.BoolFlag{
		Name:  "fast",
183
		Usage: "Enable fast syncing through state downloads",
184
	}
185 186 187 188
	LightModeFlag = cli.BoolFlag{
		Name:  "light",
		Usage: "Enable light client mode",
	}
189 190 191 192 193 194 195
	defaultSyncMode = eth.DefaultConfig.SyncMode
	SyncModeFlag    = TextMarshalerFlag{
		Name:  "syncmode",
		Usage: `Blockchain sync mode ("fast", "full", or "light")`,
		Value: &defaultSyncMode,
	}

196 197 198 199 200 201 202 203 204 205
	LightServFlag = cli.IntFlag{
		Name:  "lightserv",
		Usage: "Maximum percentage of time allowed for serving LES requests (0-90)",
		Value: 0,
	}
	LightPeersFlag = cli.IntFlag{
		Name:  "lightpeers",
		Usage: "Maximum number of LES client peers",
		Value: 20,
	}
206 207
	LightKDFFlag = cli.BoolFlag{
		Name:  "lightkdf",
208
		Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
209
	}
210 211 212 213 214 215 216 217 218 219 220
	// Performance tuning settings
	CacheFlag = cli.IntFlag{
		Name:  "cache",
		Usage: "Megabytes of memory allocated to internal caching (min 16MB / database forced)",
		Value: 128,
	}
	TrieCacheGenFlag = cli.IntFlag{
		Name:  "trie-cache-gens",
		Usage: "Number of trie node generations to keep in memory",
		Value: int(state.MaxTrieCacheGen),
	}
221 222 223 224
	// Miner settings
	MiningEnabledFlag = cli.BoolFlag{
		Name:  "mine",
		Usage: "Enable mining",
225
	}
226 227
	MinerThreadsFlag = cli.IntFlag{
		Name:  "minerthreads",
228
		Usage: "Number of CPU threads to use for mining",
229 230
		Value: runtime.NumCPU(),
	}
231
	TargetGasLimitFlag = cli.Uint64Flag{
232 233
		Name:  "targetgaslimit",
		Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine",
234
		Value: params.GenesisGasLimit.Uint64(),
235
	}
Z
zelig 已提交
236
	EtherbaseFlag = cli.StringFlag{
O
obscuren 已提交
237
		Name:  "etherbase",
238
		Usage: "Public address for block mining rewards (default = first account created)",
239
		Value: "0",
Z
zelig 已提交
240
	}
241
	GasPriceFlag = BigFlag{
242
		Name:  "gasprice",
243
		Usage: "Minimal gas price to accept for mining a transactions",
244
		Value: eth.DefaultConfig.GasPrice,
245
	}
Z
zelig 已提交
246 247
	ExtraDataFlag = cli.StringFlag{
		Name:  "extradata",
248
		Usage: "Block extra data set by the miner (default = client version)",
Z
zelig 已提交
249
	}
250
	// Account settings
Z
zelig 已提交
251 252
	UnlockedAccountFlag = cli.StringFlag{
		Name:  "unlock",
253
		Usage: "Comma separated list of accounts to unlock",
Z
zelig 已提交
254 255 256 257
		Value: "",
	}
	PasswordFileFlag = cli.StringFlag{
		Name:  "password",
258
		Usage: "Password file to use for non-inteactive password input",
Z
zelig 已提交
259
		Value: "",
Z
zelig 已提交
260
	}
261

262 263 264 265
	VMEnableDebugFlag = cli.BoolFlag{
		Name:  "vmdebug",
		Usage: "Record information useful for VM and contract debugging",
	}
266 267 268 269 270
	// Logging and debug settings
	EthStatsURLFlag = cli.StringFlag{
		Name:  "ethstats",
		Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)",
	}
271 272
	MetricsEnabledFlag = cli.BoolFlag{
		Name:  metrics.MetricsEnabledFlag,
273
		Usage: "Enable metrics collection and reporting",
274
	}
275 276 277 278
	FakePoWFlag = cli.BoolFlag{
		Name:  "fakepow",
		Usage: "Disables proof-of-work verification",
	}
279 280 281 282
	NoCompactionFlag = cli.BoolFlag{
		Name:  "nocompaction",
		Usage: "Disables db compaction after import",
	}
283 284 285
	// RPC settings
	RPCEnabledFlag = cli.BoolFlag{
		Name:  "rpc",
286
		Usage: "Enable the HTTP-RPC server",
287 288 289
	}
	RPCListenAddrFlag = cli.StringFlag{
		Name:  "rpcaddr",
290
		Usage: "HTTP-RPC server listening interface",
291
		Value: node.DefaultHTTPHost,
292 293 294
	}
	RPCPortFlag = cli.IntFlag{
		Name:  "rpcport",
295
		Usage: "HTTP-RPC server listening port",
296
		Value: node.DefaultHTTPPort,
297
	}
298 299
	RPCCORSDomainFlag = cli.StringFlag{
		Name:  "rpccorsdomain",
300
		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
301 302
		Value: "",
	}
303
	RPCApiFlag = cli.StringFlag{
304
		Name:  "rpcapi",
305
		Usage: "API's offered over the HTTP-RPC interface",
306
		Value: "",
307
	}
B
Bas van Kervel 已提交
308 309 310 311 312 313
	IPCDisabledFlag = cli.BoolFlag{
		Name:  "ipcdisable",
		Usage: "Disable the IPC-RPC server",
	}
	IPCPathFlag = DirectoryFlag{
		Name:  "ipcpath",
314
		Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)",
B
Bas van Kervel 已提交
315
	}
316
	WSEnabledFlag = cli.BoolFlag{
317
		Name:  "ws",
318 319 320 321 322
		Usage: "Enable the WS-RPC server",
	}
	WSListenAddrFlag = cli.StringFlag{
		Name:  "wsaddr",
		Usage: "WS-RPC server listening interface",
323
		Value: node.DefaultWSHost,
324 325 326 327
	}
	WSPortFlag = cli.IntFlag{
		Name:  "wsport",
		Usage: "WS-RPC server listening port",
328
		Value: node.DefaultWSPort,
329 330 331 332
	}
	WSApiFlag = cli.StringFlag{
		Name:  "wsapi",
		Usage: "API's offered over the WS-RPC interface",
333
		Value: "",
334
	}
B
Bas van Kervel 已提交
335 336 337
	WSAllowedOriginsFlag = cli.StringFlag{
		Name:  "wsorigins",
		Usage: "Origins from which to accept websockets requests",
338
		Value: "",
339
	}
340 341
	ExecFlag = cli.StringFlag{
		Name:  "exec",
342
		Usage: "Execute JavaScript statement",
343
	}
344
	PreloadJSFlag = cli.StringFlag{
345 346 347
		Name:  "preload",
		Usage: "Comma separated list of JavaScript files to preload into the console",
	}
348

349 350 351
	// Network Settings
	MaxPeersFlag = cli.IntFlag{
		Name:  "maxpeers",
352
		Usage: "Maximum number of network peers (network disabled if set to 0)",
353
		Value: 25,
354
	}
355 356 357 358 359
	MaxPendingPeersFlag = cli.IntFlag{
		Name:  "maxpendpeers",
		Usage: "Maximum number of pending connection attempts (defaults used if set to 0)",
		Value: 0,
	}
360 361 362 363 364
	ListenPortFlag = cli.IntFlag{
		Name:  "port",
		Usage: "Network listening port",
		Value: 30303,
	}
365
	BootnodesFlag = cli.StringFlag{
366
		Name:  "bootnodes",
367 368 369 370 371 372 373 374 375 376 377
		Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)",
		Value: "",
	}
	BootnodesV4Flag = cli.StringFlag{
		Name:  "bootnodesv4",
		Usage: "Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)",
		Value: "",
	}
	BootnodesV5Flag = cli.StringFlag{
		Name:  "bootnodesv5",
		Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)",
378
		Value: "",
379 380 381 382 383 384 385 386 387 388 389
	}
	NodeKeyFileFlag = cli.StringFlag{
		Name:  "nodekey",
		Usage: "P2P node key file",
	}
	NodeKeyHexFlag = cli.StringFlag{
		Name:  "nodekeyhex",
		Usage: "P2P node key as hex (for testing)",
	}
	NATFlag = cli.StringFlag{
		Name:  "nat",
390
		Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
391 392
		Value: "any",
	}
393 394 395 396
	NoDiscoverFlag = cli.BoolFlag{
		Name:  "nodiscover",
		Usage: "Disables the peer discovery mechanism (manual peer addition)",
	}
397 398 399 400
	DiscoveryV5Flag = cli.BoolFlag{
		Name:  "v5disc",
		Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
	}
401 402 403 404 405
	NetrestrictFlag = cli.StringFlag{
		Name:  "netrestrict",
		Usage: "Restricts network communication to the given IP networks (CIDR masks)",
	}

406 407
	WhisperEnabledFlag = cli.BoolFlag{
		Name:  "shh",
408
		Usage: "Enable Whisper",
409
	}
410

411
	// ATM the url is left to the user and deployment to
Z
CLI:  
zelig 已提交
412 413
	JSpathFlag = cli.StringFlag{
		Name:  "jspath",
414
		Usage: "JavaScript root path for `loadScript`",
Z
CLI:  
zelig 已提交
415 416
		Value: ".",
	}
417 418

	// Gas price oracle settings
419 420 421
	GpoBlocksFlag = cli.IntFlag{
		Name:  "gpoblocks",
		Usage: "Number of recent blocks to check for gas prices",
422
		Value: eth.DefaultConfig.GPO.Blocks,
Z
zsfelfoldi 已提交
423
	}
424 425 426
	GpoPercentileFlag = cli.IntFlag{
		Name:  "gpopercentile",
		Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices",
427
		Value: eth.DefaultConfig.GPO.Percentile,
Z
zsfelfoldi 已提交
428
	}
429 430
)

431
// MakeDataDir retrieves the currently requested data directory, terminating
432 433
// if none (or the empty string) is specified. If the node is starting a testnet,
// the a subdirectory of the specified datadir will be used.
434
func MakeDataDir(ctx *cli.Context) string {
435
	if path := ctx.GlobalString(DataDirFlag.Name); path != "" {
436
		if ctx.GlobalBool(TestnetFlag.Name) {
437
			return filepath.Join(path, "testnet")
438
		}
439 440 441
		if ctx.GlobalBool(RinkebyFlag.Name) {
			return filepath.Join(path, "rinkeby")
		}
442
		return path
443
	}
444
	Fatalf("Cannot determine default data directory, please set manually (--datadir)")
445
	return ""
446 447
}

448
// setNodeKey creates a node key from set command line flags, either loading it
449 450
// from a file or as a specified hex value. If neither flags were provided, this
// method returns nil and an emphemeral key is to be generated.
451
func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
452 453 454
	var (
		hex  = ctx.GlobalString(NodeKeyHexFlag.Name)
		file = ctx.GlobalString(NodeKeyFileFlag.Name)
455 456
		key  *ecdsa.PrivateKey
		err  error
457
	)
458 459
	switch {
	case file != "" && hex != "":
460
		Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name)
461 462
	case file != "":
		if key, err = crypto.LoadECDSA(file); err != nil {
463
			Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err)
464
		}
465
		cfg.PrivateKey = key
466 467
	case hex != "":
		if key, err = crypto.HexToECDSA(hex); err != nil {
468
			Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err)
469
		}
470
		cfg.PrivateKey = key
471 472 473
	}
}

474 475
// setNodeUserIdent creates the user identifier from CLI flags.
func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
476
	if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 {
477
		cfg.UserIdent = identity
478 479 480
	}
}

481
// setBootstrapNodes creates a list of bootstrap nodes from the command line
482
// flags, reverting to pre-configured ones if none have been specified.
483
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
484
	urls := params.MainnetBootnodes
485
	switch {
486 487 488 489 490 491
	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name):
		if ctx.GlobalIsSet(BootnodesV4Flag.Name) {
			urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",")
		} else {
			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
		}
492
	case ctx.GlobalBool(TestnetFlag.Name):
493
		urls = params.TestnetBootnodes
494 495
	case ctx.GlobalBool(RinkebyFlag.Name):
		urls = params.RinkebyBootnodes
496 497
	}

498
	cfg.BootstrapNodes = make([]*discover.Node, 0, len(urls))
499
	for _, url := range urls {
500 501
		node, err := discover.ParseNode(url)
		if err != nil {
P
Péter Szilágyi 已提交
502
			log.Error("Bootstrap URL invalid", "enode", url, "err", err)
503 504
			continue
		}
505
		cfg.BootstrapNodes = append(cfg.BootstrapNodes, node)
506 507 508
	}
}

509
// setBootstrapNodesV5 creates a list of bootstrap nodes from the command line
510
// flags, reverting to pre-configured ones if none have been specified.
511
func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
512
	urls := params.DiscoveryV5Bootnodes
513
	switch {
514 515 516 517 518 519
	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name):
		if ctx.GlobalIsSet(BootnodesV5Flag.Name) {
			urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",")
		} else {
			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
		}
520 521 522
	case ctx.GlobalBool(RinkebyFlag.Name):
		urls = params.RinkebyV5Bootnodes
	case cfg.BootstrapNodesV5 != nil:
523
		return // already set, don't apply defaults.
524 525
	}

526
	cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls))
527
	for _, url := range urls {
528 529
		node, err := discv5.ParseNode(url)
		if err != nil {
P
Péter Szilágyi 已提交
530
			log.Error("Bootstrap URL invalid", "enode", url, "err", err)
531 532
			continue
		}
533
		cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node)
534 535 536
	}
}

537
// setListenAddress creates a TCP listening address string from set command
538
// line flags.
539 540 541 542
func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
	if ctx.GlobalIsSet(ListenPortFlag.Name) {
		cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
	}
543 544
}

545
// setDiscoveryV5Address creates a UDP listening address string from set command
546
// line flags for the V5 discovery protocol.
547 548 549 550
func setDiscoveryV5Address(ctx *cli.Context, cfg *p2p.Config) {
	if ctx.GlobalIsSet(ListenPortFlag.Name) {
		cfg.DiscoveryV5Addr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)+1)
	}
551 552
}

553 554 555 556 557 558 559 560
// setNAT creates a port mapper from command line flags.
func setNAT(ctx *cli.Context, cfg *p2p.Config) {
	if ctx.GlobalIsSet(NATFlag.Name) {
		natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name))
		if err != nil {
			Fatalf("Option %s: %v", NATFlag.Name, err)
		}
		cfg.NAT = natif
561 562 563
	}
}

564 565 566
// splitAndTrim splits input separated by a comma
// and trims excessive white space from the substrings.
func splitAndTrim(input string) []string {
567 568 569 570 571 572 573
	result := strings.Split(input, ",")
	for i, r := range result {
		result[i] = strings.TrimSpace(r)
	}
	return result
}

574
// setHTTP creates the HTTP RPC listener interface string from the set
575
// command line flags, returning empty if the HTTP endpoint is disabled.
576 577 578 579 580 581 582 583 584 585 586 587
func setHTTP(ctx *cli.Context, cfg *node.Config) {
	if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" {
		cfg.HTTPHost = "127.0.0.1"
		if ctx.GlobalIsSet(RPCListenAddrFlag.Name) {
			cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name)
		}
	}

	if ctx.GlobalIsSet(RPCPortFlag.Name) {
		cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name)
	}
	if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) {
588
		cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name))
589 590
	}
	if ctx.GlobalIsSet(RPCApiFlag.Name) {
591
		cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
592 593 594
	}
}

595
// setWS creates the WebSocket RPC listener interface string from the set
596
// command line flags, returning empty if the HTTP endpoint is disabled.
597 598 599 600 601 602 603 604 605 606 607 608
func setWS(ctx *cli.Context, cfg *node.Config) {
	if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" {
		cfg.WSHost = "127.0.0.1"
		if ctx.GlobalIsSet(WSListenAddrFlag.Name) {
			cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name)
		}
	}

	if ctx.GlobalIsSet(WSPortFlag.Name) {
		cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name)
	}
	if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) {
609
		cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name))
610 611
	}
	if ctx.GlobalIsSet(WSApiFlag.Name) {
612
		cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name))
613 614 615 616 617 618 619 620 621 622 623 624
	}
}

// setIPC creates an IPC path configuration from the set command line flags,
// returning an empty string if IPC was explicitly disabled, or the set path.
func setIPC(ctx *cli.Context, cfg *node.Config) {
	checkExclusive(ctx, IPCDisabledFlag, IPCPathFlag)
	switch {
	case ctx.GlobalBool(IPCDisabledFlag.Name):
		cfg.IPCPath = ""
	case ctx.GlobalIsSet(IPCPathFlag.Name):
		cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name)
625 626 627
	}
}

628
// makeDatabaseHandles raises out the number of allowed file handles per process
629
// for Geth and returns half of the allowance to assign to the database.
630
func makeDatabaseHandles() int {
631
	if err := raiseFdLimit(2048); err != nil {
632
		Fatalf("Failed to raise file descriptor allowance: %v", err)
633 634 635
	}
	limit, err := getFdLimit()
	if err != nil {
636
		Fatalf("Failed to retrieve file descriptor allowance: %v", err)
637 638 639 640 641 642 643
	}
	if limit > 2048 { // cap database file descriptors even if more is available
		limit = 2048
	}
	return limit / 2 // Leave half for networking and other stuff
}

644 645
// MakeAddress converts an account specified directly as a hex encoded string or
// a key index in the key store to an internal account representation.
646
func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
647 648
	// If the specified account is a valid address, return it
	if common.IsHexAddress(account) {
F
Felix Lange 已提交
649
		return accounts.Account{Address: common.HexToAddress(account)}, nil
650 651 652
	}
	// Otherwise try to interpret the account as a keystore index
	index, err := strconv.Atoi(account)
653
	if err != nil || index < 0 {
F
Felix Lange 已提交
654
		return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account)
655
	}
656 657 658 659 660
	accs := ks.Accounts()
	if len(accs) <= index {
		return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs))
	}
	return accs[index], nil
661 662
}

663
// setEtherbase retrieves the etherbase either from the directly specified
664
// command line flags or from the keystore if CLI indexed.
665 666 667 668 669 670 671 672
func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) {
	if ctx.GlobalIsSet(EtherbaseFlag.Name) {
		account, err := MakeAddress(ks, ctx.GlobalString(EtherbaseFlag.Name))
		if err != nil {
			Fatalf("Option %q: %v", EtherbaseFlag.Name, err)
		}
		cfg.Etherbase = account.Address
		return
673
	}
674 675 676 677 678 679 680
	accounts := ks.Accounts()
	if (cfg.Etherbase == common.Address{}) {
		if len(accounts) > 0 {
			cfg.Etherbase = accounts[0].Address
		} else {
			log.Warn("No etherbase set and no accounts found as default")
		}
681
	}
682 683
}

684
// MakePasswordList reads password lines from the file specified by the global --password flag.
685
func MakePasswordList(ctx *cli.Context) []string {
686 687 688 689 690 691
	path := ctx.GlobalString(PasswordFileFlag.Name)
	if path == "" {
		return nil
	}
	text, err := ioutil.ReadFile(path)
	if err != nil {
692
		Fatalf("Failed to read password file: %v", err)
693 694 695 696 697
	}
	lines := strings.Split(string(text), "\n")
	// Sanitise DOS line endings.
	for i := range lines {
		lines[i] = strings.TrimRight(lines[i], "\r")
698
	}
699
	return lines
700 701
}

702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
	setNodeKey(ctx, cfg)
	setNAT(ctx, cfg)
	setListenAddress(ctx, cfg)
	setDiscoveryV5Address(ctx, cfg)
	setBootstrapNodes(ctx, cfg)
	setBootstrapNodesV5(ctx, cfg)

	if ctx.GlobalIsSet(MaxPeersFlag.Name) {
		cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
	}
	if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) {
		cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name)
	}
	if ctx.GlobalIsSet(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name) {
		cfg.NoDiscovery = true
718 719
	}

720 721 722
	// if we're running a light client or server, force enable the v5 peer discovery
	// unless it is explicitly disabled with --nodiscover note that explicitly specifying
	// --v5disc overrides --nodiscover, in which case the later only disables v4 discovery
723
	forceV5Discovery := (ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0) && !ctx.GlobalBool(NoDiscoverFlag.Name)
724 725 726 727
	if ctx.GlobalIsSet(DiscoveryV5Flag.Name) {
		cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name)
	} else if forceV5Discovery {
		cfg.DiscoveryV5 = true
728
	}
729

730 731 732
	if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" {
		list, err := netutil.ParseNetlist(netrestrict)
		if err != nil {
733
			Fatalf("Option %q: %v", NetrestrictFlag.Name, err)
734
		}
735
		cfg.NetRestrict = list
736 737
	}

738 739 740 741
	if ctx.GlobalBool(DevModeFlag.Name) {
		// --dev mode can't use p2p networking.
		cfg.MaxPeers = 0
		cfg.ListenAddr = ":0"
742
		cfg.DiscoveryV5Addr = ":0"
743 744
		cfg.NoDiscovery = true
		cfg.DiscoveryV5 = false
745 746 747
	}
}

748 749 750 751 752 753 754 755 756 757 758 759 760
// SetNodeConfig applies node-related command line flags to the config.
func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
	SetP2PConfig(ctx, &cfg.P2P)
	setIPC(ctx, cfg)
	setHTTP(ctx, cfg)
	setWS(ctx, cfg)
	setNodeUserIdent(ctx, cfg)

	switch {
	case ctx.GlobalIsSet(DataDirFlag.Name):
		cfg.DataDir = ctx.GlobalString(DataDirFlag.Name)
	case ctx.GlobalBool(DevModeFlag.Name):
		cfg.DataDir = filepath.Join(os.TempDir(), "ethereum_dev_mode")
761
	case ctx.GlobalBool(TestnetFlag.Name):
762
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet")
763 764
	case ctx.GlobalBool(RinkebyFlag.Name):
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
765 766 767 768 769 770 771 772
	}

	if ctx.GlobalIsSet(KeyStoreDirFlag.Name) {
		cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name)
	}
	if ctx.GlobalIsSet(LightKDFFlag.Name) {
		cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name)
	}
773 774 775
	if ctx.GlobalIsSet(NoUSBFlag.Name) {
		cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name)
	}
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
}

func setGPO(ctx *cli.Context, cfg *gasprice.Config) {
	if ctx.GlobalIsSet(GpoBlocksFlag.Name) {
		cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name)
	}
	if ctx.GlobalIsSet(GpoPercentileFlag.Name) {
		cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name)
	}
}

func setEthash(ctx *cli.Context, cfg *eth.Config) {
	if ctx.GlobalIsSet(EthashCacheDirFlag.Name) {
		cfg.EthashCacheDir = ctx.GlobalString(EthashCacheDirFlag.Name)
	}
	if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) {
		cfg.EthashDatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name)
	}
	if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) {
		cfg.EthashCachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name)
	}
	if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) {
		cfg.EthashCachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name)
	}
	if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) {
		cfg.EthashDatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name)
	}
	if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) {
		cfg.EthashDatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name)
	}
}

func checkExclusive(ctx *cli.Context, flags ...cli.Flag) {
	set := make([]string, 0, 1)
	for _, flag := range flags {
		if ctx.GlobalIsSet(flag.GetName()) {
			set = append(set, "--"+flag.GetName())
813 814
		}
	}
815 816
	if len(set) > 1 {
		Fatalf("flags %v can't be used at the same time", strings.Join(set, ", "))
817
	}
818 819 820 821 822
}

// SetEthConfig applies eth-related command line flags to the config.
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
	// Avoid conflicting network flags
823
	checkExclusive(ctx, DevModeFlag, TestnetFlag, RinkebyFlag)
824 825
	checkExclusive(ctx, FastSyncFlag, LightModeFlag, SyncModeFlag)

826
	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
	setEtherbase(ctx, ks, cfg)
	setGPO(ctx, &cfg.GPO)
	setEthash(ctx, cfg)

	switch {
	case ctx.GlobalIsSet(SyncModeFlag.Name):
		cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)
	case ctx.GlobalBool(FastSyncFlag.Name):
		cfg.SyncMode = downloader.FastSync
	case ctx.GlobalBool(LightModeFlag.Name):
		cfg.SyncMode = downloader.LightSync
	}
	if ctx.GlobalIsSet(LightServFlag.Name) {
		cfg.LightServ = ctx.GlobalInt(LightServFlag.Name)
	}
	if ctx.GlobalIsSet(LightPeersFlag.Name) {
		cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name)
	}
	if ctx.GlobalIsSet(NetworkIdFlag.Name) {
846
		cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name)
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
	}

	// Ethereum needs to know maxPeers to calculate the light server peer ratio.
	// TODO(fjl): ensure Ethereum can get MaxPeers from node.
	cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)

	if ctx.GlobalIsSet(CacheFlag.Name) {
		cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name)
	}
	cfg.DatabaseHandles = makeDatabaseHandles()

	if ctx.GlobalIsSet(MinerThreadsFlag.Name) {
		cfg.MinerThreads = ctx.GlobalInt(MinerThreadsFlag.Name)
	}
	if ctx.GlobalIsSet(DocRootFlag.Name) {
		cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name)
	}
	if ctx.GlobalIsSet(ExtraDataFlag.Name) {
		cfg.ExtraData = []byte(ctx.GlobalString(ExtraDataFlag.Name))
	}
	if ctx.GlobalIsSet(GasPriceFlag.Name) {
		cfg.GasPrice = GlobalBig(ctx, GasPriceFlag.Name)
	}
	if ctx.GlobalIsSet(VMEnableDebugFlag.Name) {
		// TODO(fjl): force-enable this in --dev mode
		cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
	}
874

875
	// Override any default configs for hard coded networks.
876
	switch {
877
	case ctx.GlobalBool(TestnetFlag.Name):
878
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
879
			cfg.NetworkId = 3
880
		}
881
		cfg.Genesis = core.DefaultTestnetGenesisBlock()
882 883 884 885 886
	case ctx.GlobalBool(RinkebyFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 4
		}
		cfg.Genesis = core.DefaultRinkebyGenesisBlock()
887
	case ctx.GlobalBool(DevModeFlag.Name):
888
		cfg.Genesis = core.DevGenesisBlock()
889
		if !ctx.GlobalIsSet(GasPriceFlag.Name) {
890
			cfg.GasPrice = new(big.Int)
891
		}
892
		cfg.PowTest = true
893
	}
894 895

	// TODO(fjl): move trie cache generations into config
896 897 898
	if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 {
		state.MaxTrieCacheGen = uint16(gen)
	}
899
}
900

901 902 903 904 905 906 907
// RegisterEthService adds an Ethereum client to the stack.
func RegisterEthService(stack *node.Node, cfg *eth.Config) {
	var err error
	if cfg.SyncMode == downloader.LightSync {
		err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
			return les.New(ctx, cfg)
		})
908
	} else {
909 910 911 912
		err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
			fullNode, err := eth.New(ctx, cfg)
			if fullNode != nil && cfg.LightServ > 0 {
				ls, _ := les.NewLesServer(fullNode, cfg)
913 914 915
				fullNode.AddLesServer(ls)
			}
			return fullNode, err
916 917 918 919
		})
	}
	if err != nil {
		Fatalf("Failed to register the Ethereum service: %v", err)
920
	}
921 922
}

923
// RegisterShhService configures Whisper and adds it to the given node.
924 925
func RegisterShhService(stack *node.Node) {
	if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil {
926
		Fatalf("Failed to register the Whisper service: %v", err)
927
	}
928 929
}

930 931 932 933 934 935 936 937 938 939 940 941 942
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
// th egiven node.
func RegisterEthStatsService(stack *node.Node, url string) {
	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
		// Retrieve both eth and les services
		var ethServ *eth.Ethereum
		ctx.Service(&ethServ)

		var lesServ *les.LightEthereum
		ctx.Service(&lesServ)

		return ethstats.New(url, ethServ, lesServ)
	}); err != nil {
943
		Fatalf("Failed to register the Ethereum Stats service: %v", err)
944 945 946
	}
}

947 948
// SetupNetwork configures the system for either the main net or some test network.
func SetupNetwork(ctx *cli.Context) {
949
	// TODO(fjl): move target gas limit into config
950
	params.TargetGasLimit = new(big.Int).SetUint64(ctx.GlobalUint64(TargetGasLimitFlag.Name))
951 952
}

953
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
954
func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
955 956
	var (
		cache   = ctx.GlobalInt(CacheFlag.Name)
957
		handles = makeDatabaseHandles()
958
	)
959 960 961 962
	name := "chaindata"
	if ctx.GlobalBool(LightModeFlag.Name) {
		name = "lightchaindata"
	}
963
	chainDb, err := stack.OpenDatabase(name, cache, handles)
964
	if err != nil {
965
		Fatalf("Could not open database: %v", err)
966
	}
967 968 969
	return chainDb
}

F
Felix Lange 已提交
970 971 972
func MakeGenesis(ctx *cli.Context) *core.Genesis {
	var genesis *core.Genesis
	switch {
973
	case ctx.GlobalBool(TestnetFlag.Name):
F
Felix Lange 已提交
974
		genesis = core.DefaultTestnetGenesisBlock()
975 976
	case ctx.GlobalBool(RinkebyFlag.Name):
		genesis = core.DefaultRinkebyGenesisBlock()
F
Felix Lange 已提交
977 978 979 980 981 982
	case ctx.GlobalBool(DevModeFlag.Name):
		genesis = core.DevGenesisBlock()
	}
	return genesis
}

983
// MakeChain creates a chain manager from set command line flags.
984
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
985
	var err error
986
	chainDb = MakeChainDatabase(ctx, stack)
987

988
	engine := ethash.NewFaker()
989
	if !ctx.GlobalBool(FakePoWFlag.Name) {
990
		engine = ethash.New("", 1, 0, "", 1, 0)
991
	}
F
Felix Lange 已提交
992 993 994 995 996
	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
	if err != nil {
		Fatalf("%v", err)
	}
	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
997
	chain, err = core.NewBlockChain(chainDb, config, engine, new(event.TypeMux), vmcfg)
O
obscuren 已提交
998
	if err != nil {
F
Felix Lange 已提交
999
		Fatalf("Can't create BlockChain: %v", err)
O
obscuren 已提交
1000
	}
1001
	return chain, chainDb
1002
}
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019

// MakeConsolePreloads retrieves the absolute paths for the console JavaScript
// scripts to preload before starting.
func MakeConsolePreloads(ctx *cli.Context) []string {
	// Skip preloading if there's nothing to preload
	if ctx.GlobalString(PreloadJSFlag.Name) == "" {
		return nil
	}
	// Otherwise resolve absolute paths and return them
	preloads := []string{}

	assets := ctx.GlobalString(JSpathFlag.Name)
	for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") {
		preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file)))
	}
	return preloads
}
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043

// MigrateFlags sets the global flag from a local flag when it's set.
// This is a temporary function used for migrating old command/flags to the
// new format.
//
// e.g. geth account new --keystore /tmp/mykeystore --lightkdf
//
// is equivalent after calling this method with:
//
// geth --keystore /tmp/mykeystore --lightkdf account new
//
// This allows the use of the existing configuration functionality.
// When all flags are migrated this function can be removed and the existing
// configuration functionality must be changed that is uses local flags
func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error {
	return func(ctx *cli.Context) error {
		for _, name := range ctx.FlagNames() {
			if ctx.IsSet(name) {
				ctx.GlobalSet(name, ctx.String(name))
			}
		}
		return action(ctx)
	}
}