flags.go 58.9 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
	"errors"
23
	"fmt"
24
	"io/ioutil"
25
	"math/big"
26
	"os"
27
	"path/filepath"
28
	"strconv"
29
	"strings"
30
	"time"
31

F
Felix Lange 已提交
32
	"github.com/ethereum/go-ethereum/accounts"
33
	"github.com/ethereum/go-ethereum/accounts/keystore"
Z
zelig 已提交
34
	"github.com/ethereum/go-ethereum/common"
35
	"github.com/ethereum/go-ethereum/common/fdlimit"
36 37
	"github.com/ethereum/go-ethereum/consensus"
	"github.com/ethereum/go-ethereum/consensus/clique"
38
	"github.com/ethereum/go-ethereum/consensus/ethash"
39
	"github.com/ethereum/go-ethereum/core"
40
	"github.com/ethereum/go-ethereum/core/vm"
41
	"github.com/ethereum/go-ethereum/crypto"
42
	"github.com/ethereum/go-ethereum/dashboard"
43
	"github.com/ethereum/go-ethereum/eth"
44 45
	"github.com/ethereum/go-ethereum/eth/downloader"
	"github.com/ethereum/go-ethereum/eth/gasprice"
46
	"github.com/ethereum/go-ethereum/ethdb"
47
	"github.com/ethereum/go-ethereum/ethstats"
48
	"github.com/ethereum/go-ethereum/graphql"
49
	"github.com/ethereum/go-ethereum/les"
50
	"github.com/ethereum/go-ethereum/log"
B
Bas van Kervel 已提交
51
	"github.com/ethereum/go-ethereum/metrics"
52
	"github.com/ethereum/go-ethereum/metrics/influxdb"
53
	"github.com/ethereum/go-ethereum/miner"
54
	"github.com/ethereum/go-ethereum/node"
55
	"github.com/ethereum/go-ethereum/p2p"
56
	"github.com/ethereum/go-ethereum/p2p/discv5"
57
	"github.com/ethereum/go-ethereum/p2p/enode"
58
	"github.com/ethereum/go-ethereum/p2p/nat"
59
	"github.com/ethereum/go-ethereum/p2p/netutil"
60
	"github.com/ethereum/go-ethereum/params"
61
	"github.com/ethereum/go-ethereum/rpc"
62
	whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
63
	pcsclite "github.com/gballet/go-libpcsclite"
64
	cli "gopkg.in/urfave/cli.v1"
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:
72
	{{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
73 74 75 76 77 78 79
	{{end}}{{end}}{{if .categorizedFlags}}
{{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS:
{{range $categorized.Flags}}{{"\t"}}{{.}}
{{end}}
{{end}}{{end}}`
)

80 81 82 83 84 85 86 87 88 89 90 91 92 93
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}}
`

94
	cli.CommandHelpTemplate = CommandHelpTemplate
95 96
}

F
Felix Lange 已提交
97
// NewApp creates an app with sane defaults.
98
func NewApp(gitCommit, gitDate, usage string) *cli.App {
F
Felix Lange 已提交
99
	app := cli.NewApp()
100
	app.Name = filepath.Base(os.Args[0])
F
Felix Lange 已提交
101 102
	app.Author = ""
	app.Email = ""
103
	app.Version = params.VersionWithCommit(gitCommit, gitDate)
F
Felix Lange 已提交
104 105 106 107
	app.Usage = usage
	return app
}

108 109 110 111 112 113 114 115 116
// 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
117
	DataDirFlag = DirectoryFlag{
118
		Name:  "datadir",
119
		Usage: "Data directory for the databases and keystore",
120
		Value: DirectoryString{node.DefaultDataDir()},
121
	}
122 123 124 125
	AncientFlag = DirectoryFlag{
		Name:  "datadir.ancient",
		Usage: "Data directory for ancient chain segments (default = inside chaindata)",
	}
K
Kobi Gurkan 已提交
126 127 128 129
	KeyStoreDirFlag = DirectoryFlag{
		Name:  "keystore",
		Usage: "Directory for the keystore (default = inside the datadir)",
	}
130 131
	NoUSBFlag = cli.BoolFlag{
		Name:  "nousb",
O
Oli Bye 已提交
132
		Usage: "Disables monitoring for and managing USB hardware wallets",
133
	}
134 135 136 137 138
	SmartCardDaemonPathFlag = cli.StringFlag{
		Name:  "pcscdpath",
		Usage: "Path to the smartcard daemon (pcscd) socket file",
		Value: pcsclite.PCSCDSockName,
	}
139
	NetworkIdFlag = cli.Uint64Flag{
Z
zelig 已提交
140
		Name:  "networkid",
141
		Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)",
142
		Value: eth.DefaultConfig.NetworkId,
Z
zelig 已提交
143
	}
144
	TestnetFlag = cli.BoolFlag{
145
		Name:  "testnet",
146
		Usage: "Ropsten network: pre-configured proof-of-work test network",
147
	}
148 149 150 151
	RinkebyFlag = cli.BoolFlag{
		Name:  "rinkeby",
		Usage: "Rinkeby network: pre-configured proof-of-authority test network",
	}
152 153 154 155
	GoerliFlag = cli.BoolFlag{
		Name:  "goerli",
		Usage: "Görli network: pre-configured proof-of-authority test network",
	}
156
	DeveloperFlag = cli.BoolFlag{
157
		Name:  "dev",
158 159 160 161 162
		Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
	}
	DeveloperPeriodFlag = cli.IntFlag{
		Name:  "dev.period",
		Usage: "Block period to use in developer mode (0 = mine only if transaction pending)",
163
	}
164 165
	IdentityFlag = cli.StringFlag{
		Name:  "identity",
166
		Usage: "Custom node name",
167
	}
Z
zelig 已提交
168 169 170
	DocRootFlag = DirectoryFlag{
		Name:  "docroot",
		Usage: "Document Root for HTTPClient file scheme",
171
		Value: DirectoryString{homeDir()},
Z
zelig 已提交
172
	}
173 174
	ExitWhenSyncedFlag = cli.BoolFlag{
		Name:  "exitwhensynced",
175
		Usage: "Exits after block synchronisation completes",
176
	}
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
	IterativeOutputFlag = cli.BoolFlag{
		Name:  "iterative",
		Usage: "Print streaming JSON iteratively, delimited by newlines",
	}
	ExcludeStorageFlag = cli.BoolFlag{
		Name:  "nostorage",
		Usage: "Exclude storage entries (save db lookups)",
	}
	IncludeIncompletesFlag = cli.BoolFlag{
		Name:  "incompletes",
		Usage: "Include accounts for which we don't have the address (missing preimage)",
	}
	ExcludeCodeFlag = cli.BoolFlag{
		Name:  "nocode",
		Usage: "Exclude contract code (save db lookups)",
	}
193 194 195 196 197 198
	defaultSyncMode = eth.DefaultConfig.SyncMode
	SyncModeFlag    = TextMarshalerFlag{
		Name:  "syncmode",
		Usage: `Blockchain sync mode ("fast", "full", or "light")`,
		Value: &defaultSyncMode,
	}
199 200 201 202 203
	GCModeFlag = cli.StringFlag{
		Name:  "gcmode",
		Usage: `Blockchain garbage collection mode ("full", "archive")`,
		Value: "full",
	}
204 205 206 207 208 209 210 211
	LightKDFFlag = cli.BoolFlag{
		Name:  "lightkdf",
		Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
	}
	WhitelistFlag = cli.StringFlag{
		Name:  "whitelist",
		Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)",
	}
212 213
	// Light server and client settings
	LightLegacyServFlag = cli.IntFlag{ // Deprecated in favor of light.serve, remove in 2021
214
		Name:  "lightserv",
215 216 217 218 219
		Usage: "Maximum percentage of time allowed for serving LES requests (deprecated, use --light.serve)",
		Value: eth.DefaultConfig.LightServ,
	}
	LightServeFlag = cli.IntFlag{
		Name:  "light.serve",
220
		Usage: "Maximum percentage of time allowed for serving LES requests (multi-threaded processing allows values over 100)",
221
		Value: eth.DefaultConfig.LightServ,
222
	}
223 224 225 226
	LightIngressFlag = cli.IntFlag{
		Name:  "light.ingress",
		Usage: "Incoming bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)",
		Value: eth.DefaultConfig.LightIngress,
227
	}
228 229 230 231
	LightEgressFlag = cli.IntFlag{
		Name:  "light.egress",
		Usage: "Outgoing bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)",
		Value: eth.DefaultConfig.LightEgress,
232
	}
233
	LightLegacyPeersFlag = cli.IntFlag{ // Deprecated in favor of light.maxpeers, remove in 2021
234
		Name:  "lightpeers",
235 236 237 238 239 240
		Usage: "Maximum number of light clients to serve, or light servers to attach to  (deprecated, use --light.maxpeers)",
		Value: eth.DefaultConfig.LightPeers,
	}
	LightMaxPeersFlag = cli.IntFlag{
		Name:  "light.maxpeers",
		Usage: "Maximum number of light clients to serve, or light servers to attach to",
241
		Value: eth.DefaultConfig.LightPeers,
242
	}
243 244 245 246
	UltraLightServersFlag = cli.StringFlag{
		Name:  "ulc.servers",
		Usage: "List of trusted ultra-light servers",
		Value: strings.Join(eth.DefaultConfig.UltraLightServers, ","),
247
	}
248 249 250 251 252 253 254 255
	UltraLightFractionFlag = cli.IntFlag{
		Name:  "ulc.fraction",
		Usage: "Minimum % of trusted ultra-light servers required to announce a new head",
		Value: eth.DefaultConfig.UltraLightFraction,
	}
	UltraLightOnlyAnnounceFlag = cli.BoolFlag{
		Name:  "ulc.onlyannounce",
		Usage: "Ultra light server sends announcements only",
256
	}
257 258
	// Dashboard settings
	DashboardEnabledFlag = cli.BoolFlag{
259
		Name:  "dashboard",
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
		Usage: "Enable the dashboard",
	}
	DashboardAddrFlag = cli.StringFlag{
		Name:  "dashboard.addr",
		Usage: "Dashboard listening interface",
		Value: dashboard.DefaultConfig.Host,
	}
	DashboardPortFlag = cli.IntFlag{
		Name:  "dashboard.host",
		Usage: "Dashboard listening port",
		Value: dashboard.DefaultConfig.Port,
	}
	DashboardRefreshFlag = cli.DurationFlag{
		Name:  "dashboard.refresh",
		Usage: "Dashboard metrics collection refresh rate",
		Value: dashboard.DefaultConfig.Refresh,
	}
277 278 279 280 281 282 283 284
	// Ethash settings
	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)",
285
		Value: eth.DefaultConfig.Ethash.CachesInMem,
286 287 288 289
	}
	EthashCachesOnDiskFlag = cli.IntFlag{
		Name:  "ethash.cachesondisk",
		Usage: "Number of recent ethash caches to keep on disk (16MB each)",
290
		Value: eth.DefaultConfig.Ethash.CachesOnDisk,
291 292 293 294
	}
	EthashDatasetDirFlag = DirectoryFlag{
		Name:  "ethash.dagdir",
		Usage: "Directory to store the ethash mining DAGs (default = inside home folder)",
295
		Value: DirectoryString{eth.DefaultConfig.Ethash.DatasetDir},
296 297 298 299
	}
	EthashDatasetsInMemoryFlag = cli.IntFlag{
		Name:  "ethash.dagsinmem",
		Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
300
		Value: eth.DefaultConfig.Ethash.DatasetsInMem,
301 302 303 304
	}
	EthashDatasetsOnDiskFlag = cli.IntFlag{
		Name:  "ethash.dagsondisk",
		Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
305
		Value: eth.DefaultConfig.Ethash.DatasetsOnDisk,
306 307
	}
	// Transaction pool settings
308 309 310 311
	TxPoolLocalsFlag = cli.StringFlag{
		Name:  "txpool.locals",
		Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)",
	}
312 313 314 315
	TxPoolNoLocalsFlag = cli.BoolFlag{
		Name:  "txpool.nolocals",
		Usage: "Disables price exemptions for locally submitted transactions",
	}
316 317 318 319 320 321 322 323 324 325
	TxPoolJournalFlag = cli.StringFlag{
		Name:  "txpool.journal",
		Usage: "Disk journal for local transaction to survive node restarts",
		Value: core.DefaultTxPoolConfig.Journal,
	}
	TxPoolRejournalFlag = cli.DurationFlag{
		Name:  "txpool.rejournal",
		Usage: "Time interval to regenerate the local transaction journal",
		Value: core.DefaultTxPoolConfig.Rejournal,
	}
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
	TxPoolPriceLimitFlag = cli.Uint64Flag{
		Name:  "txpool.pricelimit",
		Usage: "Minimum gas price limit to enforce for acceptance into the pool",
		Value: eth.DefaultConfig.TxPool.PriceLimit,
	}
	TxPoolPriceBumpFlag = cli.Uint64Flag{
		Name:  "txpool.pricebump",
		Usage: "Price bump percentage to replace an already existing transaction",
		Value: eth.DefaultConfig.TxPool.PriceBump,
	}
	TxPoolAccountSlotsFlag = cli.Uint64Flag{
		Name:  "txpool.accountslots",
		Usage: "Minimum number of executable transaction slots guaranteed per account",
		Value: eth.DefaultConfig.TxPool.AccountSlots,
	}
	TxPoolGlobalSlotsFlag = cli.Uint64Flag{
		Name:  "txpool.globalslots",
		Usage: "Maximum number of executable transaction slots for all accounts",
		Value: eth.DefaultConfig.TxPool.GlobalSlots,
	}
	TxPoolAccountQueueFlag = cli.Uint64Flag{
		Name:  "txpool.accountqueue",
		Usage: "Maximum number of non-executable transaction slots permitted per account",
		Value: eth.DefaultConfig.TxPool.AccountQueue,
	}
	TxPoolGlobalQueueFlag = cli.Uint64Flag{
		Name:  "txpool.globalqueue",
		Usage: "Maximum number of non-executable transaction slots for all accounts",
		Value: eth.DefaultConfig.TxPool.GlobalQueue,
	}
	TxPoolLifetimeFlag = cli.DurationFlag{
		Name:  "txpool.lifetime",
		Usage: "Maximum amount of time non-executable transaction are queued",
		Value: eth.DefaultConfig.TxPool.Lifetime,
	}
361 362 363
	// Performance tuning settings
	CacheFlag = cli.IntFlag{
		Name:  "cache",
364
		Usage: "Megabytes of memory allocated to internal caching (default = 4096 mainnet full node, 128 light mode)",
365 366 367 368 369
		Value: 1024,
	}
	CacheDatabaseFlag = cli.IntFlag{
		Name:  "cache.database",
		Usage: "Percentage of cache memory allowance to use for database io",
370 371 372 373
		Value: 50,
	}
	CacheTrieFlag = cli.IntFlag{
		Name:  "cache.trie",
374
		Usage: "Percentage of cache memory allowance to use for trie caching (default = 25% full mode, 50% archive mode)",
375
		Value: 25,
376 377 378
	}
	CacheGCFlag = cli.IntFlag{
		Name:  "cache.gc",
379
		Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)",
380
		Value: 25,
381
	}
382 383 384 385
	CacheNoPrefetchFlag = cli.BoolFlag{
		Name:  "cache.noprefetch",
		Usage: "Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data)",
	}
386 387 388 389
	// Miner settings
	MiningEnabledFlag = cli.BoolFlag{
		Name:  "mine",
		Usage: "Enable mining",
390
	}
391
	MinerThreadsFlag = cli.IntFlag{
392
		Name:  "miner.threads",
393
		Usage: "Number of CPU threads to use for mining",
394 395
		Value: 0,
	}
396 397 398 399 400
	MinerLegacyThreadsFlag = cli.IntFlag{
		Name:  "minerthreads",
		Usage: "Number of CPU threads to use for mining (deprecated, use --miner.threads)",
		Value: 0,
	}
401 402 403
	MinerNotifyFlag = cli.StringFlag{
		Name:  "miner.notify",
		Usage: "Comma separated HTTP URL list to notify of new work packages",
404
	}
405 406 407
	MinerGasTargetFlag = cli.Uint64Flag{
		Name:  "miner.gastarget",
		Usage: "Target gas floor for mined blocks",
408
		Value: eth.DefaultConfig.Miner.GasFloor,
409 410
	}
	MinerLegacyGasTargetFlag = cli.Uint64Flag{
411
		Name:  "targetgaslimit",
412
		Usage: "Target gas floor for mined blocks (deprecated, use --miner.gastarget)",
413
		Value: eth.DefaultConfig.Miner.GasFloor,
414 415 416 417
	}
	MinerGasLimitFlag = cli.Uint64Flag{
		Name:  "miner.gaslimit",
		Usage: "Target gas ceiling for mined blocks",
418
		Value: eth.DefaultConfig.Miner.GasCeil,
419
	}
420 421
	MinerGasPriceFlag = BigFlag{
		Name:  "miner.gasprice",
422
		Usage: "Minimum gas price for mining a transaction",
423
		Value: eth.DefaultConfig.Miner.GasPrice,
Z
zelig 已提交
424
	}
425
	MinerLegacyGasPriceFlag = BigFlag{
426
		Name:  "gasprice",
427
		Usage: "Minimum gas price for mining a transaction (deprecated, use --miner.gasprice)",
428
		Value: eth.DefaultConfig.Miner.GasPrice,
429
	}
430 431 432 433 434 435 436 437 438 439 440 441
	MinerEtherbaseFlag = cli.StringFlag{
		Name:  "miner.etherbase",
		Usage: "Public address for block mining rewards (default = first account)",
		Value: "0",
	}
	MinerLegacyEtherbaseFlag = cli.StringFlag{
		Name:  "etherbase",
		Usage: "Public address for block mining rewards (default = first account, deprecated, use --miner.etherbase)",
		Value: "0",
	}
	MinerExtraDataFlag = cli.StringFlag{
		Name:  "miner.extradata",
442
		Usage: "Block extra data set by the miner (default = client version)",
Z
zelig 已提交
443
	}
444 445 446 447
	MinerLegacyExtraDataFlag = cli.StringFlag{
		Name:  "extradata",
		Usage: "Block extra data set by the miner (default = client version, deprecated, use --miner.extradata)",
	}
448 449
	MinerRecommitIntervalFlag = cli.DurationFlag{
		Name:  "miner.recommit",
450
		Usage: "Time interval to recreate the block being mined",
451
		Value: eth.DefaultConfig.Miner.Recommit,
452
	}
453 454 455 456
	MinerNoVerfiyFlag = cli.BoolFlag{
		Name:  "miner.noverify",
		Usage: "Disable remote sealing verification",
	}
457
	// Account settings
Z
zelig 已提交
458 459
	UnlockedAccountFlag = cli.StringFlag{
		Name:  "unlock",
460
		Usage: "Comma separated list of accounts to unlock",
Z
zelig 已提交
461 462 463 464
		Value: "",
	}
	PasswordFileFlag = cli.StringFlag{
		Name:  "password",
A
ayeowch 已提交
465
		Usage: "Password file to use for non-interactive password input",
Z
zelig 已提交
466
		Value: "",
Z
zelig 已提交
467
	}
468 469 470 471 472
	ExternalSignerFlag = cli.StringFlag{
		Name:  "signer",
		Usage: "External signer (url or path to ipc file)",
		Value: "",
	}
473 474 475 476
	VMEnableDebugFlag = cli.BoolFlag{
		Name:  "vmdebug",
		Usage: "Record information useful for VM and contract debugging",
	}
477 478 479 480
	InsecureUnlockAllowedFlag = cli.BoolFlag{
		Name:  "allow-insecure-unlock",
		Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http",
	}
481 482 483 484
	RPCGlobalGasCap = cli.Uint64Flag{
		Name:  "rpc.gascap",
		Usage: "Sets a cap on gas that can be used in eth_call/estimateGas",
	}
485 486 487 488 489
	// Logging and debug settings
	EthStatsURLFlag = cli.StringFlag{
		Name:  "ethstats",
		Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)",
	}
490 491 492 493
	FakePoWFlag = cli.BoolFlag{
		Name:  "fakepow",
		Usage: "Disables proof-of-work verification",
	}
494 495 496 497
	NoCompactionFlag = cli.BoolFlag{
		Name:  "nocompaction",
		Usage: "Disables db compaction after import",
	}
498
	// RPC settings
499 500 501 502 503 504 505 506
	IPCDisabledFlag = cli.BoolFlag{
		Name:  "ipcdisable",
		Usage: "Disable the IPC-RPC server",
	}
	IPCPathFlag = DirectoryFlag{
		Name:  "ipcpath",
		Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)",
	}
507 508
	RPCEnabledFlag = cli.BoolFlag{
		Name:  "rpc",
509
		Usage: "Enable the HTTP-RPC server",
510 511 512
	}
	RPCListenAddrFlag = cli.StringFlag{
		Name:  "rpcaddr",
513
		Usage: "HTTP-RPC server listening interface",
514
		Value: node.DefaultHTTPHost,
515 516 517
	}
	RPCPortFlag = cli.IntFlag{
		Name:  "rpcport",
518
		Usage: "HTTP-RPC server listening port",
519
		Value: node.DefaultHTTPPort,
520
	}
521 522
	RPCCORSDomainFlag = cli.StringFlag{
		Name:  "rpccorsdomain",
523
		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
524 525
		Value: "",
	}
526 527 528
	RPCVirtualHostsFlag = cli.StringFlag{
		Name:  "rpcvhosts",
		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
529
		Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
530
	}
531
	RPCApiFlag = cli.StringFlag{
532
		Name:  "rpcapi",
533
		Usage: "API's offered over the HTTP-RPC interface",
534
		Value: "",
535
	}
536
	WSEnabledFlag = cli.BoolFlag{
537
		Name:  "ws",
538 539 540 541 542
		Usage: "Enable the WS-RPC server",
	}
	WSListenAddrFlag = cli.StringFlag{
		Name:  "wsaddr",
		Usage: "WS-RPC server listening interface",
543
		Value: node.DefaultWSHost,
544 545 546 547
	}
	WSPortFlag = cli.IntFlag{
		Name:  "wsport",
		Usage: "WS-RPC server listening port",
548
		Value: node.DefaultWSPort,
549 550 551 552
	}
	WSApiFlag = cli.StringFlag{
		Name:  "wsapi",
		Usage: "API's offered over the WS-RPC interface",
553
		Value: "",
554
	}
B
Bas van Kervel 已提交
555 556 557
	WSAllowedOriginsFlag = cli.StringFlag{
		Name:  "wsorigins",
		Usage: "Origins from which to accept websockets requests",
558
		Value: "",
559
	}
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
	GraphQLEnabledFlag = cli.BoolFlag{
		Name:  "graphql",
		Usage: "Enable the GraphQL server",
	}
	GraphQLListenAddrFlag = cli.StringFlag{
		Name:  "graphql.addr",
		Usage: "GraphQL server listening interface",
		Value: node.DefaultGraphQLHost,
	}
	GraphQLPortFlag = cli.IntFlag{
		Name:  "graphql.port",
		Usage: "GraphQL server listening port",
		Value: node.DefaultGraphQLPort,
	}
	GraphQLCORSDomainFlag = cli.StringFlag{
		Name:  "graphql.corsdomain",
		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
		Value: "",
	}
	GraphQLVirtualHostsFlag = cli.StringFlag{
		Name:  "graphql.vhosts",
		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
		Value: strings.Join(node.DefaultConfig.GraphQLVirtualHosts, ","),
	}
584 585
	ExecFlag = cli.StringFlag{
		Name:  "exec",
586
		Usage: "Execute JavaScript statement",
587
	}
588
	PreloadJSFlag = cli.StringFlag{
589 590 591
		Name:  "preload",
		Usage: "Comma separated list of JavaScript files to preload into the console",
	}
592

593 594 595
	// Network Settings
	MaxPeersFlag = cli.IntFlag{
		Name:  "maxpeers",
596
		Usage: "Maximum number of network peers (network disabled if set to 0)",
597
		Value: node.DefaultConfig.P2P.MaxPeers,
598
	}
599 600 601
	MaxPendingPeersFlag = cli.IntFlag{
		Name:  "maxpendpeers",
		Usage: "Maximum number of pending connection attempts (defaults used if set to 0)",
602
		Value: node.DefaultConfig.P2P.MaxPendingPeers,
603
	}
604 605 606 607 608
	ListenPortFlag = cli.IntFlag{
		Name:  "port",
		Usage: "Network listening port",
		Value: 30303,
	}
609
	BootnodesFlag = cli.StringFlag{
610
		Name:  "bootnodes",
611 612 613 614 615 616 617 618 619 620 621
		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)",
622
		Value: "",
623 624 625 626 627 628 629 630 631 632 633
	}
	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",
634
		Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
635 636
		Value: "any",
	}
637 638 639 640
	NoDiscoverFlag = cli.BoolFlag{
		Name:  "nodiscover",
		Usage: "Disables the peer discovery mechanism (manual peer addition)",
	}
641 642 643 644
	DiscoveryV5Flag = cli.BoolFlag{
		Name:  "v5disc",
		Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
	}
645 646 647 648 649
	NetrestrictFlag = cli.StringFlag{
		Name:  "netrestrict",
		Usage: "Restricts network communication to the given IP networks (CIDR masks)",
	}

650
	// ATM the url is left to the user and deployment to
Z
CLI:  
zelig 已提交
651 652
	JSpathFlag = cli.StringFlag{
		Name:  "jspath",
653
		Usage: "JavaScript root path for `loadScript`",
Z
CLI:  
zelig 已提交
654 655
		Value: ".",
	}
656 657

	// Gas price oracle settings
658 659 660
	GpoBlocksFlag = cli.IntFlag{
		Name:  "gpoblocks",
		Usage: "Number of recent blocks to check for gas prices",
661
		Value: eth.DefaultConfig.GPO.Blocks,
Z
zsfelfoldi 已提交
662
	}
663 664 665
	GpoPercentileFlag = cli.IntFlag{
		Name:  "gpopercentile",
		Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices",
666
		Value: eth.DefaultConfig.GPO.Percentile,
Z
zsfelfoldi 已提交
667
	}
668 669 670 671 672 673 674 675 676 677 678 679 680 681
	WhisperEnabledFlag = cli.BoolFlag{
		Name:  "shh",
		Usage: "Enable Whisper",
	}
	WhisperMaxMessageSizeFlag = cli.IntFlag{
		Name:  "shh.maxmessagesize",
		Usage: "Max message size accepted",
		Value: int(whisper.DefaultMaxMessageSize),
	}
	WhisperMinPOWFlag = cli.Float64Flag{
		Name:  "shh.pow",
		Usage: "Minimum POW accepted",
		Value: whisper.DefaultMinimumPoW,
	}
682 683 684 685
	WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{
		Name:  "shh.restrict-light",
		Usage: "Restrict connection between two whisper light clients",
	}
686 687 688

	// Metrics flags
	MetricsEnabledFlag = cli.BoolFlag{
689
		Name:  "metrics",
690 691
		Usage: "Enable metrics collection and reporting",
	}
692 693 694 695
	MetricsEnabledExpensiveFlag = cli.BoolFlag{
		Name:  "metrics.expensive",
		Usage: "Enable expensive metrics collection and reporting",
	}
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
	MetricsEnableInfluxDBFlag = cli.BoolFlag{
		Name:  "metrics.influxdb",
		Usage: "Enable metrics export/push to an external InfluxDB database",
	}
	MetricsInfluxDBEndpointFlag = cli.StringFlag{
		Name:  "metrics.influxdb.endpoint",
		Usage: "InfluxDB API endpoint to report metrics to",
		Value: "http://localhost:8086",
	}
	MetricsInfluxDBDatabaseFlag = cli.StringFlag{
		Name:  "metrics.influxdb.database",
		Usage: "InfluxDB database name to push reported metrics to",
		Value: "geth",
	}
	MetricsInfluxDBUsernameFlag = cli.StringFlag{
		Name:  "metrics.influxdb.username",
		Usage: "Username to authorize access to the database",
		Value: "test",
	}
	MetricsInfluxDBPasswordFlag = cli.StringFlag{
		Name:  "metrics.influxdb.password",
		Usage: "Password to authorize access to the database",
		Value: "test",
	}
720 721 722
	// Tags are part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB.
	// For example `host` tag could be used so that we can group all nodes and average a measurement
	// across all of them, but also so that we can select a specific node and inspect its measurements.
723
	// https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key
724 725 726 727
	MetricsInfluxDBTagsFlag = cli.StringFlag{
		Name:  "metrics.influxdb.tags",
		Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements",
		Value: "host=localhost",
728
	}
729 730 731 732 733 734 735 736 737 738 739

	EWASMInterpreterFlag = cli.StringFlag{
		Name:  "vm.ewasm",
		Usage: "External ewasm configuration (default = built-in interpreter)",
		Value: "",
	}
	EVMInterpreterFlag = cli.StringFlag{
		Name:  "vm.evm",
		Usage: "External EVM configuration (default = built-in interpreter)",
		Value: "",
	}
740 741
)

742
// MakeDataDir retrieves the currently requested data directory, terminating
743 744
// 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.
745
func MakeDataDir(ctx *cli.Context) string {
746
	if path := ctx.GlobalString(DataDirFlag.Name); path != "" {
747
		if ctx.GlobalBool(TestnetFlag.Name) {
748
			return filepath.Join(path, "testnet")
749
		}
750 751 752
		if ctx.GlobalBool(RinkebyFlag.Name) {
			return filepath.Join(path, "rinkeby")
		}
753 754 755
		if ctx.GlobalBool(GoerliFlag.Name) {
			return filepath.Join(path, "goerli")
		}
756
		return path
757
	}
758
	Fatalf("Cannot determine default data directory, please set manually (--datadir)")
759
	return ""
760 761
}

762
// setNodeKey creates a node key from set command line flags, either loading it
763 764
// 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.
765
func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
766 767 768
	var (
		hex  = ctx.GlobalString(NodeKeyHexFlag.Name)
		file = ctx.GlobalString(NodeKeyFileFlag.Name)
769 770
		key  *ecdsa.PrivateKey
		err  error
771
	)
772 773
	switch {
	case file != "" && hex != "":
774
		Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name)
775 776
	case file != "":
		if key, err = crypto.LoadECDSA(file); err != nil {
777
			Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err)
778
		}
779
		cfg.PrivateKey = key
780 781
	case hex != "":
		if key, err = crypto.HexToECDSA(hex); err != nil {
782
			Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err)
783
		}
784
		cfg.PrivateKey = key
785 786 787
	}
}

788 789
// setNodeUserIdent creates the user identifier from CLI flags.
func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
790
	if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 {
791
		cfg.UserIdent = identity
792 793 794
	}
}

795
// setBootstrapNodes creates a list of bootstrap nodes from the command line
796
// flags, reverting to pre-configured ones if none have been specified.
797
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
798
	urls := params.MainnetBootnodes
799
	switch {
800 801 802 803 804 805
	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), ",")
		}
806
	case ctx.GlobalBool(TestnetFlag.Name):
807
		urls = params.TestnetBootnodes
808 809
	case ctx.GlobalBool(RinkebyFlag.Name):
		urls = params.RinkebyBootnodes
810 811
	case ctx.GlobalBool(GoerliFlag.Name):
		urls = params.GoerliBootnodes
812 813
	case cfg.BootstrapNodes != nil:
		return // already set, don't apply defaults.
814 815
	}

816
	cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls))
817
	for _, url := range urls {
818
		if url != "" {
819
			node, err := enode.Parse(enode.ValidSchemes, url)
820 821
			if err != nil {
				log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
822
				continue
823 824
			}
			cfg.BootstrapNodes = append(cfg.BootstrapNodes, node)
825 826 827 828
		}
	}
}

829
// setBootstrapNodesV5 creates a list of bootstrap nodes from the command line
830
// flags, reverting to pre-configured ones if none have been specified.
831
func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
832
	urls := params.DiscoveryV5Bootnodes
833
	switch {
834 835 836 837 838 839
	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), ",")
		}
840
	case ctx.GlobalBool(RinkebyFlag.Name):
841
		urls = params.RinkebyBootnodes
842 843
	case ctx.GlobalBool(GoerliFlag.Name):
		urls = params.GoerliBootnodes
844
	case cfg.BootstrapNodesV5 != nil:
845
		return // already set, don't apply defaults.
846 847
	}

848
	cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls))
849
	for _, url := range urls {
850 851 852 853 854 855 856
		if url != "" {
			node, err := discv5.ParseNode(url)
			if err != nil {
				log.Error("Bootstrap URL invalid", "enode", url, "err", err)
				continue
			}
			cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node)
857 858 859 860
		}
	}
}

861
// setListenAddress creates a TCP listening address string from set command
862
// line flags.
863 864 865 866
func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
	if ctx.GlobalIsSet(ListenPortFlag.Name) {
		cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
	}
867 868
}

869 870 871 872 873 874 875 876
// 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
877 878 879
	}
}

880 881 882
// splitAndTrim splits input separated by a comma
// and trims excessive white space from the substrings.
func splitAndTrim(input string) []string {
883 884 885 886 887 888 889
	result := strings.Split(input, ",")
	for i, r := range result {
		result[i] = strings.TrimSpace(r)
	}
	return result
}

890
// setHTTP creates the HTTP RPC listener interface string from the set
891
// command line flags, returning empty if the HTTP endpoint is disabled.
892 893 894 895 896 897 898 899 900 901 902
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) {
903
		cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name))
904 905
	}
	if ctx.GlobalIsSet(RPCApiFlag.Name) {
906
		cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
907
	}
908 909 910
	if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) {
		cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
	}
911 912
}

913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930
// setGraphQL creates the GraphQL listener interface string from the set
// command line flags, returning empty if the GraphQL endpoint is disabled.
func setGraphQL(ctx *cli.Context, cfg *node.Config) {
	if ctx.GlobalBool(GraphQLEnabledFlag.Name) && cfg.GraphQLHost == "" {
		cfg.GraphQLHost = "127.0.0.1"
		if ctx.GlobalIsSet(GraphQLListenAddrFlag.Name) {
			cfg.GraphQLHost = ctx.GlobalString(GraphQLListenAddrFlag.Name)
		}
	}
	cfg.GraphQLPort = ctx.GlobalInt(GraphQLPortFlag.Name)
	if ctx.GlobalIsSet(GraphQLCORSDomainFlag.Name) {
		cfg.GraphQLCors = splitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name))
	}
	if ctx.GlobalIsSet(GraphQLVirtualHostsFlag.Name) {
		cfg.GraphQLVirtualHosts = splitAndTrim(ctx.GlobalString(GraphQLVirtualHostsFlag.Name))
	}
}

931
// setWS creates the WebSocket RPC listener interface string from the set
932
// command line flags, returning empty if the HTTP endpoint is disabled.
933 934 935 936 937 938 939 940 941 942 943
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) {
944
		cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name))
945 946
	}
	if ctx.GlobalIsSet(WSApiFlag.Name) {
947
		cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name))
948 949 950 951 952 953
	}
}

// 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) {
954
	CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag)
955 956 957 958 959
	switch {
	case ctx.GlobalBool(IPCDisabledFlag.Name):
		cfg.IPCPath = ""
	case ctx.GlobalIsSet(IPCPathFlag.Name):
		cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name)
960 961 962
	}
}

963 964
// setLes configures the les server and ultra light client settings from the command line flags.
func setLes(ctx *cli.Context, cfg *eth.Config) {
965 966 967 968 969 970 971 972
	if ctx.GlobalIsSet(LightLegacyServFlag.Name) {
		cfg.LightServ = ctx.GlobalInt(LightLegacyServFlag.Name)
	}
	if ctx.GlobalIsSet(LightServeFlag.Name) {
		cfg.LightServ = ctx.GlobalInt(LightServeFlag.Name)
	}
	if ctx.GlobalIsSet(LightIngressFlag.Name) {
		cfg.LightIngress = ctx.GlobalInt(LightIngressFlag.Name)
973
	}
974 975
	if ctx.GlobalIsSet(LightEgressFlag.Name) {
		cfg.LightEgress = ctx.GlobalInt(LightEgressFlag.Name)
976
	}
977 978
	if ctx.GlobalIsSet(LightLegacyPeersFlag.Name) {
		cfg.LightPeers = ctx.GlobalInt(LightLegacyPeersFlag.Name)
979
	}
980 981
	if ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
		cfg.LightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name)
982
	}
983 984
	if ctx.GlobalIsSet(UltraLightServersFlag.Name) {
		cfg.UltraLightServers = strings.Split(ctx.GlobalString(UltraLightServersFlag.Name), ",")
985
	}
986 987
	if ctx.GlobalIsSet(UltraLightFractionFlag.Name) {
		cfg.UltraLightFraction = ctx.GlobalInt(UltraLightFractionFlag.Name)
988
	}
989 990 991
	if cfg.UltraLightFraction <= 0 && cfg.UltraLightFraction > 100 {
		log.Error("Ultra light fraction is invalid", "had", cfg.UltraLightFraction, "updated", eth.DefaultConfig.UltraLightFraction)
		cfg.UltraLightFraction = eth.DefaultConfig.UltraLightFraction
992
	}
993 994
	if ctx.GlobalIsSet(UltraLightOnlyAnnounceFlag.Name) {
		cfg.UltraLightOnlyAnnounce = ctx.GlobalBool(UltraLightOnlyAnnounceFlag.Name)
995 996 997
	}
}

998
// makeDatabaseHandles raises out the number of allowed file handles per process
999
// for Geth and returns half of the allowance to assign to the database.
1000
func makeDatabaseHandles() int {
1001
	limit, err := fdlimit.Maximum()
1002
	if err != nil {
1003
		Fatalf("Failed to retrieve file descriptor allowance: %v", err)
1004
	}
1005 1006
	raised, err := fdlimit.Raise(uint64(limit))
	if err != nil {
1007
		Fatalf("Failed to raise file descriptor allowance: %v", err)
1008
	}
1009
	return int(raised / 2) // Leave half for networking and other stuff
1010 1011
}

1012 1013
// MakeAddress converts an account specified directly as a hex encoded string or
// a key index in the key store to an internal account representation.
1014
func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
1015 1016
	// If the specified account is a valid address, return it
	if common.IsHexAddress(account) {
F
Felix Lange 已提交
1017
		return accounts.Account{Address: common.HexToAddress(account)}, nil
1018 1019 1020
	}
	// Otherwise try to interpret the account as a keystore index
	index, err := strconv.Atoi(account)
1021
	if err != nil || index < 0 {
F
Felix Lange 已提交
1022
		return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account)
1023
	}
1024 1025 1026 1027 1028 1029
	log.Warn("-------------------------------------------------------------------")
	log.Warn("Referring to accounts by order in the keystore folder is dangerous!")
	log.Warn("This functionality is deprecated and will be removed in the future!")
	log.Warn("Please use explicit addresses! (can search via `geth account list`)")
	log.Warn("-------------------------------------------------------------------")

1030 1031 1032 1033 1034
	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
1035 1036
}

1037
// setEtherbase retrieves the etherbase either from the directly specified
1038
// command line flags or from the keystore if CLI indexed.
1039
func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) {
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
	// Extract the current etherbase, new flag overriding legacy one
	var etherbase string
	if ctx.GlobalIsSet(MinerLegacyEtherbaseFlag.Name) {
		etherbase = ctx.GlobalString(MinerLegacyEtherbaseFlag.Name)
	}
	if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) {
		etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name)
	}
	// Convert the etherbase into an address and configure it
	if etherbase != "" {
1050 1051 1052 1053 1054
		if ks != nil {
			account, err := MakeAddress(ks, etherbase)
			if err != nil {
				Fatalf("Invalid miner etherbase: %v", err)
			}
1055
			cfg.Miner.Etherbase = account.Address
1056 1057
		} else {
			Fatalf("No etherbase configured")
1058
		}
1059
	}
1060 1061
}

1062
// MakePasswordList reads password lines from the file specified by the global --password flag.
1063
func MakePasswordList(ctx *cli.Context) []string {
1064 1065 1066 1067 1068 1069
	path := ctx.GlobalString(PasswordFileFlag.Name)
	if path == "" {
		return nil
	}
	text, err := ioutil.ReadFile(path)
	if err != nil {
1070
		Fatalf("Failed to read password file: %v", err)
1071 1072 1073 1074 1075
	}
	lines := strings.Split(string(text), "\n")
	// Sanitise DOS line endings.
	for i := range lines {
		lines[i] = strings.TrimRight(lines[i], "\r")
1076
	}
1077
	return lines
1078 1079
}

1080 1081 1082 1083 1084 1085 1086
func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
	setNodeKey(ctx, cfg)
	setNAT(ctx, cfg)
	setListenAddress(ctx, cfg)
	setBootstrapNodes(ctx, cfg)
	setBootstrapNodesV5(ctx, cfg)

1087
	lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light"
1088
	lightServer := (ctx.GlobalInt(LightLegacyServFlag.Name) != 0 || ctx.GlobalInt(LightServeFlag.Name) != 0)
1089

1090 1091 1092 1093
	lightPeers := ctx.GlobalInt(LightLegacyPeersFlag.Name)
	if ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
		lightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name)
	}
1094 1095
	if ctx.GlobalIsSet(MaxPeersFlag.Name) {
		cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
1096
		if lightServer && !ctx.GlobalIsSet(LightLegacyPeersFlag.Name) && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
1097 1098
			cfg.MaxPeers += lightPeers
		}
1099 1100 1101 1102
	} else {
		if lightServer {
			cfg.MaxPeers += lightPeers
		}
1103
		if lightClient && (ctx.GlobalIsSet(LightLegacyPeersFlag.Name) || ctx.GlobalIsSet(LightMaxPeersFlag.Name)) && cfg.MaxPeers < lightPeers {
1104 1105
			cfg.MaxPeers = lightPeers
		}
1106
	}
1107 1108 1109 1110 1111 1112 1113 1114 1115
	if !(lightClient || lightServer) {
		lightPeers = 0
	}
	ethPeers := cfg.MaxPeers - lightPeers
	if lightClient {
		ethPeers = 0
	}
	log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers)

1116 1117 1118
	if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) {
		cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name)
	}
1119
	if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient {
1120
		cfg.NoDiscovery = true
1121 1122
	}

1123 1124 1125
	// 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
1126
	forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name)
1127 1128 1129 1130
	if ctx.GlobalIsSet(DiscoveryV5Flag.Name) {
		cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name)
	} else if forceV5Discovery {
		cfg.DiscoveryV5 = true
1131
	}
1132

1133 1134 1135
	if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" {
		list, err := netutil.ParseNetlist(netrestrict)
		if err != nil {
1136
			Fatalf("Option %q: %v", NetrestrictFlag.Name, err)
1137
		}
1138
		cfg.NetRestrict = list
1139 1140
	}

1141
	if ctx.GlobalBool(DeveloperFlag.Name) {
1142 1143 1144 1145 1146
		// --dev mode can't use p2p networking.
		cfg.MaxPeers = 0
		cfg.ListenAddr = ":0"
		cfg.NoDiscovery = true
		cfg.DiscoveryV5 = false
1147 1148 1149
	}
}

1150 1151 1152 1153 1154
// 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)
1155
	setGraphQL(ctx, cfg)
1156 1157
	setWS(ctx, cfg)
	setNodeUserIdent(ctx, cfg)
1158
	setDataDir(ctx, cfg)
1159
	setSmartCard(ctx, cfg)
1160

1161 1162 1163 1164
	if ctx.GlobalIsSet(ExternalSignerFlag.Name) {
		cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name)
	}

1165 1166 1167 1168 1169 1170
	if ctx.GlobalIsSet(KeyStoreDirFlag.Name) {
		cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name)
	}
	if ctx.GlobalIsSet(LightKDFFlag.Name) {
		cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name)
	}
1171 1172 1173
	if ctx.GlobalIsSet(NoUSBFlag.Name) {
		cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name)
	}
1174 1175 1176
	if ctx.GlobalIsSet(InsecureUnlockAllowedFlag.Name) {
		cfg.InsecureUnlockAllowed = ctx.GlobalBool(InsecureUnlockAllowedFlag.Name)
	}
1177 1178
}

1179 1180 1181 1182 1183 1184 1185 1186 1187
func setSmartCard(ctx *cli.Context, cfg *node.Config) {
	// Skip enabling smartcards if no path is set
	path := ctx.GlobalString(SmartCardDaemonPathFlag.Name)
	if path == "" {
		return
	}
	// Sanity check that the smartcard path is valid
	fi, err := os.Stat(path)
	if err != nil {
1188
		log.Info("Smartcard socket not found, disabling", "err", err)
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
		return
	}
	if fi.Mode()&os.ModeType != os.ModeSocket {
		log.Error("Invalid smartcard daemon path", "path", path, "type", fi.Mode().String())
		return
	}
	// Smartcard daemon path exists and is a socket, enable it
	cfg.SmartCardDaemonPath = path
}

1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
func setDataDir(ctx *cli.Context, cfg *node.Config) {
	switch {
	case ctx.GlobalIsSet(DataDirFlag.Name):
		cfg.DataDir = ctx.GlobalString(DataDirFlag.Name)
	case ctx.GlobalBool(DeveloperFlag.Name):
		cfg.DataDir = "" // unless explicitly requested, use memory databases
	case ctx.GlobalBool(TestnetFlag.Name):
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet")
	case ctx.GlobalBool(RinkebyFlag.Name):
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
1209 1210
	case ctx.GlobalBool(GoerliFlag.Name):
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
1211 1212 1213
	}
}

1214 1215 1216 1217 1218 1219 1220 1221 1222
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)
	}
}

1223
func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) {
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
	if ctx.GlobalIsSet(TxPoolLocalsFlag.Name) {
		locals := strings.Split(ctx.GlobalString(TxPoolLocalsFlag.Name), ",")
		for _, account := range locals {
			if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) {
				Fatalf("Invalid account in --txpool.locals: %s", trimmed)
			} else {
				cfg.Locals = append(cfg.Locals, common.HexToAddress(account))
			}
		}
	}
1234 1235 1236
	if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) {
		cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name)
	}
1237 1238 1239 1240 1241 1242
	if ctx.GlobalIsSet(TxPoolJournalFlag.Name) {
		cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name)
	}
	if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) {
		cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name)
	}
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
	if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) {
		cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name)
	}
	if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) {
		cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name)
	}
	if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) {
		cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name)
	}
	if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) {
		cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name)
	}
	if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) {
		cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name)
	}
	if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) {
		cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name)
	}
	if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) {
		cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name)
	}
}

1266 1267
func setEthash(ctx *cli.Context, cfg *eth.Config) {
	if ctx.GlobalIsSet(EthashCacheDirFlag.Name) {
1268
		cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name)
1269 1270
	}
	if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) {
1271
		cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name)
1272 1273
	}
	if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) {
1274
		cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name)
1275 1276
	}
	if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) {
1277
		cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name)
1278 1279
	}
	if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) {
1280
		cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name)
1281 1282
	}
	if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) {
1283
		cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name)
1284 1285 1286
	}
}

1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
func setMiner(ctx *cli.Context, cfg *miner.Config) {
	if ctx.GlobalIsSet(MinerNotifyFlag.Name) {
		cfg.Notify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",")
	}
	if ctx.GlobalIsSet(MinerLegacyExtraDataFlag.Name) {
		cfg.ExtraData = []byte(ctx.GlobalString(MinerLegacyExtraDataFlag.Name))
	}
	if ctx.GlobalIsSet(MinerExtraDataFlag.Name) {
		cfg.ExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name))
	}
	if ctx.GlobalIsSet(MinerLegacyGasTargetFlag.Name) {
		cfg.GasFloor = ctx.GlobalUint64(MinerLegacyGasTargetFlag.Name)
	}
	if ctx.GlobalIsSet(MinerGasTargetFlag.Name) {
		cfg.GasFloor = ctx.GlobalUint64(MinerGasTargetFlag.Name)
	}
	if ctx.GlobalIsSet(MinerGasLimitFlag.Name) {
		cfg.GasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name)
	}
	if ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
		cfg.GasPrice = GlobalBig(ctx, MinerLegacyGasPriceFlag.Name)
	}
	if ctx.GlobalIsSet(MinerGasPriceFlag.Name) {
		cfg.GasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name)
	}
	if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) {
		cfg.Recommit = ctx.Duration(MinerRecommitIntervalFlag.Name)
	}
	if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) {
		cfg.Noverify = ctx.Bool(MinerNoVerfiyFlag.Name)
	}
}

1320
func setWhitelist(ctx *cli.Context, cfg *eth.Config) {
1321 1322 1323 1324 1325 1326 1327 1328 1329
	whitelist := ctx.GlobalString(WhitelistFlag.Name)
	if whitelist == "" {
		return
	}
	cfg.Whitelist = make(map[uint64]common.Hash)
	for _, entry := range strings.Split(whitelist, ",") {
		parts := strings.Split(entry, "=")
		if len(parts) != 2 {
			Fatalf("Invalid whitelist entry: %s", entry)
1330
		}
1331 1332 1333 1334 1335 1336 1337 1338 1339
		number, err := strconv.ParseUint(parts[0], 0, 64)
		if err != nil {
			Fatalf("Invalid whitelist block number %s: %v", parts[0], err)
		}
		var hash common.Hash
		if err = hash.UnmarshalText([]byte(parts[1])); err != nil {
			Fatalf("Invalid whitelist hash %s: %v", parts[1], err)
		}
		cfg.Whitelist[number] = hash
1340 1341 1342
	}
}

1343
// CheckExclusive verifies that only a single instance of the provided flags was
1344 1345
// set by the user. Each flag might optionally be followed by a string type to
// specialize it further.
1346
func CheckExclusive(ctx *cli.Context, args ...interface{}) {
1347
	set := make([]string, 0, 1)
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
	for i := 0; i < len(args); i++ {
		// Make sure the next argument is a flag and skip if not set
		flag, ok := args[i].(cli.Flag)
		if !ok {
			panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i]))
		}
		// Check if next arg extends current and expand its name if so
		name := flag.GetName()

		if i+1 < len(args) {
			switch option := args[i+1].(type) {
			case string:
1360
				// Extended flag check, make sure value set doesn't conflict with passed in option
1361 1362
				if ctx.GlobalString(flag.GetName()) == option {
					name += "=" + option
1363
					set = append(set, "--"+name)
1364
				}
1365
				// shift arguments and continue
1366
				i++
1367
				continue
1368 1369 1370 1371 1372 1373 1374

			case cli.Flag:
			default:
				panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1]))
			}
		}
		// Mark the flag if it's set
1375
		if ctx.GlobalIsSet(flag.GetName()) {
1376
			set = append(set, "--"+name)
1377 1378
		}
	}
1379
	if len(set) > 1 {
1380
		Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", "))
1381
	}
1382 1383
}

1384 1385
// SetShhConfig applies shh-related command line flags to the config.
func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
1386 1387
	if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) {
		cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name))
1388
	}
1389 1390
	if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) {
		cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name)
1391
	}
1392 1393 1394
	if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) {
		cfg.RestrictConnectionBetweenLightClients = true
	}
1395 1396
}

1397 1398 1399
// 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
1400
	CheckExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag, GoerliFlag)
1401 1402 1403
	CheckExclusive(ctx, LightLegacyServFlag, LightServeFlag, SyncModeFlag, "light")
	CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer

1404 1405 1406 1407
	var ks *keystore.KeyStore
	if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 {
		ks = keystores[0].(*keystore.KeyStore)
	}
1408 1409
	setEtherbase(ctx, ks, cfg)
	setGPO(ctx, &cfg.GPO)
1410
	setTxPool(ctx, &cfg.TxPool)
1411
	setEthash(ctx, cfg)
1412
	setMiner(ctx, &cfg.Miner)
1413
	setWhitelist(ctx, cfg)
1414
	setLes(ctx, cfg)
1415

1416
	if ctx.GlobalIsSet(SyncModeFlag.Name) {
1417 1418 1419
		cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)
	}
	if ctx.GlobalIsSet(NetworkIdFlag.Name) {
1420
		cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name)
1421
	}
1422 1423
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) {
		cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
1424 1425
	}
	cfg.DatabaseHandles = makeDatabaseHandles()
1426 1427 1428
	if ctx.GlobalIsSet(AncientFlag.Name) {
		cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name)
	}
1429

1430 1431 1432 1433
	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
	}
	cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"
1434
	cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name)
1435

1436 1437 1438
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
		cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
	}
1439
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
1440
		cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
1441
	}
1442 1443 1444 1445 1446 1447 1448
	if ctx.GlobalIsSet(DocRootFlag.Name) {
		cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name)
	}
	if ctx.GlobalIsSet(VMEnableDebugFlag.Name) {
		// TODO(fjl): force-enable this in --dev mode
		cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
	}
1449

1450 1451 1452 1453 1454 1455 1456
	if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) {
		cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name)
	}

	if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
		cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
	}
1457 1458 1459
	if ctx.GlobalIsSet(RPCGlobalGasCap.Name) {
		cfg.RPCGasCap = new(big.Int).SetUint64(ctx.GlobalUint64(RPCGlobalGasCap.Name))
	}
1460

1461
	// Override any default configs for hard coded networks.
1462
	switch {
1463
	case ctx.GlobalBool(TestnetFlag.Name):
1464
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
1465
			cfg.NetworkId = 3
1466
		}
1467
		cfg.Genesis = core.DefaultTestnetGenesisBlock()
1468 1469 1470 1471 1472
	case ctx.GlobalBool(RinkebyFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 4
		}
		cfg.Genesis = core.DefaultRinkebyGenesisBlock()
1473 1474 1475 1476 1477
	case ctx.GlobalBool(GoerliFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 5
		}
		cfg.Genesis = core.DefaultGoerliGenesisBlock()
1478
	case ctx.GlobalBool(DeveloperFlag.Name):
1479 1480 1481
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 1337
		}
1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500
		// Create new developer account or reuse existing one
		var (
			developer accounts.Account
			err       error
		)
		if accs := ks.Accounts(); len(accs) > 0 {
			developer = ks.Accounts()[0]
		} else {
			developer, err = ks.NewAccount("")
			if err != nil {
				Fatalf("Failed to create developer account: %v", err)
			}
		}
		if err := ks.Unlock(developer, ""); err != nil {
			Fatalf("Failed to unlock developer account: %v", err)
		}
		log.Info("Using developer account", "address", developer.Address)

		cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address)
1501
		if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
1502
			cfg.Miner.GasPrice = big.NewInt(1)
1503 1504
		}
	}
1505
}
1506

1507 1508 1509 1510 1511 1512 1513
// SetDashboardConfig applies dashboard related command line flags to the config.
func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
	cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
	cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
	cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
}

1514 1515 1516 1517 1518 1519 1520
// 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)
		})
1521
	} else {
1522 1523 1524 1525
		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)
1526 1527 1528
				fullNode.AddLesServer(ls)
			}
			return fullNode, err
1529 1530 1531 1532
		})
	}
	if err != nil {
		Fatalf("Failed to register the Ethereum service: %v", err)
1533
	}
1534 1535
}

1536
// RegisterDashboardService adds a dashboard to the stack.
1537
func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) {
1538
	stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
1539
		return dashboard.New(cfg, commit, ctx.ResolvePath("logs")), nil
1540 1541 1542
	})
}

1543
// RegisterShhService configures Whisper and adds it to the given node.
1544 1545 1546 1547
func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
	if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) {
		return whisper.New(cfg), nil
	}); err != nil {
1548
		Fatalf("Failed to register the Whisper service: %v", err)
1549
	}
1550 1551
}

1552
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
S
Sarlor 已提交
1553
// the given node.
1554 1555 1556 1557 1558 1559 1560 1561 1562
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)

1563
		// Let ethstats use whichever is not nil
1564 1565
		return ethstats.New(url, ethServ, lesServ)
	}); err != nil {
1566
		Fatalf("Failed to register the Ethereum Stats service: %v", err)
1567 1568 1569
	}
}

1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
		// Try to construct the GraphQL service backed by a full node
		var ethServ *eth.Ethereum
		if err := ctx.Service(&ethServ); err == nil {
			return graphql.New(ethServ.APIBackend, endpoint, cors, vhosts, timeouts)
		}
		// Try to construct the GraphQL service backed by a light node
		var lesServ *les.LightEthereum
		if err := ctx.Service(&lesServ); err == nil {
			return graphql.New(lesServ.ApiBackend, endpoint, cors, vhosts, timeouts)
		}
		// Well, this should not have happened, bail out
		return nil, errors.New("no Ethereum service")
	}); err != nil {
		Fatalf("Failed to register the GraphQL service: %v", err)
	}
}

1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601
func SetupMetrics(ctx *cli.Context) {
	if metrics.Enabled {
		log.Info("Enabling metrics collection")
		var (
			enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name)
			endpoint     = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name)
			database     = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name)
			username     = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name)
			password     = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name)
		)

		if enableExport {
1602 1603
			tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name))

1604
			log.Info("Enabling metrics export to InfluxDB")
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621

			go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap)
		}
	}
}

func SplitTagsFlag(tagsFlag string) map[string]string {
	tags := strings.Split(tagsFlag, ",")
	tagsMap := map[string]string{}

	for _, t := range tags {
		if t != "" {
			kv := strings.Split(t, "=")

			if len(kv) == 2 {
				tagsMap[kv[0]] = kv[1]
			}
1622 1623
		}
	}
1624 1625

	return tagsMap
1626 1627
}

1628
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
1629
func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
1630
	var (
1631
		cache   = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
1632
		handles = makeDatabaseHandles()
1633
	)
1634
	name := "chaindata"
1635
	if ctx.GlobalString(SyncModeFlag.Name) == "light" {
1636 1637
		name = "lightchaindata"
	}
1638
	chainDb, err := stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "")
1639
	if err != nil {
1640
		Fatalf("Could not open database: %v", err)
1641
	}
1642 1643 1644
	return chainDb
}

F
Felix Lange 已提交
1645 1646 1647
func MakeGenesis(ctx *cli.Context) *core.Genesis {
	var genesis *core.Genesis
	switch {
1648
	case ctx.GlobalBool(TestnetFlag.Name):
F
Felix Lange 已提交
1649
		genesis = core.DefaultTestnetGenesisBlock()
1650 1651
	case ctx.GlobalBool(RinkebyFlag.Name):
		genesis = core.DefaultRinkebyGenesisBlock()
1652 1653
	case ctx.GlobalBool(GoerliFlag.Name):
		genesis = core.DefaultGoerliGenesisBlock()
1654 1655
	case ctx.GlobalBool(DeveloperFlag.Name):
		Fatalf("Developer chains are ephemeral")
F
Felix Lange 已提交
1656 1657 1658 1659
	}
	return genesis
}

1660
// MakeChain creates a chain manager from set command line flags.
1661
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
1662
	var err error
1663
	chainDb = MakeChainDatabase(ctx, stack)
F
Felix Lange 已提交
1664 1665 1666 1667
	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
	if err != nil {
		Fatalf("%v", err)
	}
1668 1669 1670 1671 1672 1673
	var engine consensus.Engine
	if config.Clique != nil {
		engine = clique.New(config.Clique, chainDb)
	} else {
		engine = ethash.NewFaker()
		if !ctx.GlobalBool(FakePoWFlag.Name) {
1674 1675 1676 1677 1678 1679 1680
			engine = ethash.New(ethash.Config{
				CacheDir:       stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir),
				CachesInMem:    eth.DefaultConfig.Ethash.CachesInMem,
				CachesOnDisk:   eth.DefaultConfig.Ethash.CachesOnDisk,
				DatasetDir:     stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir),
				DatasetsInMem:  eth.DefaultConfig.Ethash.DatasetsInMem,
				DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk,
1681
			}, nil, false)
1682 1683
		}
	}
1684 1685 1686 1687
	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
	}
	cache := &core.CacheConfig{
1688 1689 1690 1691 1692
		TrieCleanLimit:      eth.DefaultConfig.TrieCleanCache,
		TrieCleanNoPrefetch: ctx.GlobalBool(CacheNoPrefetchFlag.Name),
		TrieDirtyLimit:      eth.DefaultConfig.TrieDirtyCache,
		TrieDirtyDisabled:   ctx.GlobalString(GCModeFlag.Name) == "archive",
		TrieTimeLimit:       eth.DefaultConfig.TrieTimeout,
1693 1694 1695
	}
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
		cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
1696 1697
	}
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
1698
		cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
1699
	}
F
Felix Lange 已提交
1700
	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
1701
	chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil)
O
obscuren 已提交
1702
	if err != nil {
F
Felix Lange 已提交
1703
		Fatalf("Can't create BlockChain: %v", err)
O
obscuren 已提交
1704
	}
1705
	return chain, chainDb
1706
}
1707 1708 1709 1710 1711 1712 1713 1714 1715

// 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
1716
	var preloads []string
1717 1718 1719 1720 1721 1722 1723

	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
}
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747

// 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)
	}
}