flags.go 66.8 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"
24
	"io/ioutil"
25
	"math"
26
	"math/big"
27
	"os"
28
	"path/filepath"
29
	godebug "runtime/debug"
30
	"strconv"
31
	"strings"
32 33
	"text/tabwriter"
	"text/template"
34
	"time"
35

F
Felix Lange 已提交
36
	"github.com/ethereum/go-ethereum/accounts"
37
	"github.com/ethereum/go-ethereum/accounts/keystore"
Z
zelig 已提交
38
	"github.com/ethereum/go-ethereum/common"
39
	"github.com/ethereum/go-ethereum/common/fdlimit"
40 41
	"github.com/ethereum/go-ethereum/consensus"
	"github.com/ethereum/go-ethereum/consensus/clique"
42
	"github.com/ethereum/go-ethereum/consensus/ethash"
43
	"github.com/ethereum/go-ethereum/core"
44
	"github.com/ethereum/go-ethereum/core/rawdb"
45
	"github.com/ethereum/go-ethereum/core/vm"
46 47
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/eth"
48
	"github.com/ethereum/go-ethereum/eth/downloader"
49
	"github.com/ethereum/go-ethereum/eth/ethconfig"
50
	"github.com/ethereum/go-ethereum/eth/gasprice"
51
	"github.com/ethereum/go-ethereum/eth/tracers"
52
	"github.com/ethereum/go-ethereum/ethdb"
53
	"github.com/ethereum/go-ethereum/ethstats"
54
	"github.com/ethereum/go-ethereum/graphql"
R
rene 已提交
55
	"github.com/ethereum/go-ethereum/internal/ethapi"
56
	"github.com/ethereum/go-ethereum/internal/flags"
57
	"github.com/ethereum/go-ethereum/les"
58
	"github.com/ethereum/go-ethereum/log"
B
Bas van Kervel 已提交
59
	"github.com/ethereum/go-ethereum/metrics"
60
	"github.com/ethereum/go-ethereum/metrics/exp"
61
	"github.com/ethereum/go-ethereum/metrics/influxdb"
62
	"github.com/ethereum/go-ethereum/miner"
63
	"github.com/ethereum/go-ethereum/node"
64
	"github.com/ethereum/go-ethereum/p2p"
65
	"github.com/ethereum/go-ethereum/p2p/enode"
66
	"github.com/ethereum/go-ethereum/p2p/nat"
67
	"github.com/ethereum/go-ethereum/p2p/netutil"
68
	"github.com/ethereum/go-ethereum/params"
69
	pcsclite "github.com/gballet/go-libpcsclite"
70
	gopsutil "github.com/shirou/gopsutil/mem"
71
	"gopkg.in/urfave/cli.v1"
72 73
)

74 75 76 77 78 79 80 81 82 83 84 85 86
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}}
`
87
	cli.CommandHelpTemplate = flags.CommandHelpTemplate
88
	cli.HelpPrinter = printHelp
89 90
}

91 92 93 94 95 96 97 98 99 100 101
func printHelp(out io.Writer, templ string, data interface{}) {
	funcMap := template.FuncMap{"join": strings.Join}
	t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
	w := tabwriter.NewWriter(out, 38, 8, 2, ' ', 0)
	err := t.Execute(w, data)
	if err != nil {
		panic(err)
	}
	w.Flush()
}

102 103 104 105 106 107 108 109 110
// 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
111
	DataDirFlag = DirectoryFlag{
112
		Name:  "datadir",
113
		Usage: "Data directory for the databases and keystore",
114
		Value: DirectoryString(node.DefaultDataDir()),
115
	}
116 117 118 119
	AncientFlag = DirectoryFlag{
		Name:  "datadir.ancient",
		Usage: "Data directory for ancient chain segments (default = inside chaindata)",
	}
120 121 122 123
	MinFreeDiskSpaceFlag = DirectoryFlag{
		Name:  "datadir.minfreedisk",
		Usage: "Minimum free disk space in MB, once reached triggers auto shut down (default = --cache.gc converted to MB, 0 = disabled)",
	}
K
Kobi Gurkan 已提交
124 125 126 127
	KeyStoreDirFlag = DirectoryFlag{
		Name:  "keystore",
		Usage: "Directory for the keystore (default = inside the datadir)",
	}
128 129
	NoUSBFlag = cli.BoolFlag{
		Name:  "nousb",
130 131 132 133 134
		Usage: "Disables monitoring for and managing USB hardware wallets (deprecated)",
	}
	USBFlag = cli.BoolFlag{
		Name:  "usb",
		Usage: "Enable monitoring and management of USB hardware wallets",
135
	}
136 137 138 139 140
	SmartCardDaemonPathFlag = cli.StringFlag{
		Name:  "pcscdpath",
		Usage: "Path to the smartcard daemon (pcscd) socket file",
		Value: pcsclite.PCSCDSockName,
	}
141
	NetworkIdFlag = cli.Uint64Flag{
Z
zelig 已提交
142
		Name:  "networkid",
143
		Usage: "Explicitly set network id (integer)(For testnets: use --ropsten, --rinkeby, --goerli instead)",
144
		Value: ethconfig.Defaults.NetworkId,
Z
zelig 已提交
145
	}
146 147 148 149
	MainnetFlag = cli.BoolFlag{
		Name:  "mainnet",
		Usage: "Ethereum mainnet",
	}
150 151 152
	GoerliFlag = cli.BoolFlag{
		Name:  "goerli",
		Usage: "Görli network: pre-configured proof-of-authority test network",
153
	}
154 155 156
	CalaverasFlag = cli.BoolFlag{
		Name:  "calaveras",
		Usage: "Calaveras network: pre-configured proof-of-authority shortlived test network.",
157
	}
158 159 160 161
	RinkebyFlag = cli.BoolFlag{
		Name:  "rinkeby",
		Usage: "Rinkeby network: pre-configured proof-of-authority test network",
	}
162 163 164
	RopstenFlag = cli.BoolFlag{
		Name:  "ropsten",
		Usage: "Ropsten network: pre-configured proof-of-work test network",
165
	}
166
	DeveloperFlag = cli.BoolFlag{
167
		Name:  "dev",
168 169 170 171 172
		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)",
173
	}
174 175
	IdentityFlag = cli.StringFlag{
		Name:  "identity",
176
		Usage: "Custom node name",
177
	}
Z
zelig 已提交
178 179 180
	DocRootFlag = DirectoryFlag{
		Name:  "docroot",
		Usage: "Document Root for HTTPClient file scheme",
181
		Value: DirectoryString(HomeDir()),
Z
zelig 已提交
182
	}
183 184
	ExitWhenSyncedFlag = cli.BoolFlag{
		Name:  "exitwhensynced",
185
		Usage: "Exits after block synchronisation completes",
186
	}
187
	IterativeOutputFlag = cli.BoolTFlag{
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
		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)",
	}
203 204 205 206 207 208 209 210 211 212
	StartKeyFlag = cli.StringFlag{
		Name:  "start",
		Usage: "Start position. Either a hash or address",
		Value: "0x0000000000000000000000000000000000000000000000000000000000000000",
	}
	DumpLimitFlag = cli.Uint64Flag{
		Name:  "limit",
		Usage: "Max number of elements (0 = no limit)",
		Value: 0,
	}
213
	defaultSyncMode = ethconfig.Defaults.SyncMode
214 215
	SyncModeFlag    = TextMarshalerFlag{
		Name:  "syncmode",
216
		Usage: `Blockchain sync mode ("fast", "full", "snap" or "light")`,
217 218
		Value: &defaultSyncMode,
	}
219 220 221 222 223
	GCModeFlag = cli.StringFlag{
		Name:  "gcmode",
		Usage: `Blockchain garbage collection mode ("full", "archive")`,
		Value: "full",
	}
224
	SnapshotFlag = cli.BoolTFlag{
225
		Name:  "snapshot",
226
		Usage: `Enables snapshot-database mode (default = enable)`,
227
	}
228
	TxLookupLimitFlag = cli.Uint64Flag{
229
		Name:  "txlookuplimit",
230 231
		Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)",
		Value: ethconfig.Defaults.TxLookupLimit,
232
	}
233 234 235 236 237 238 239 240
	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>)",
	}
241 242 243 244 245
	BloomFilterSizeFlag = cli.Uint64Flag{
		Name:  "bloomfilter.size",
		Usage: "Megabytes of memory allocated to bloom-filter for pruning",
		Value: 2048,
	}
246 247 248
	OverrideLondonFlag = cli.Uint64Flag{
		Name:  "override.london",
		Usage: "Manually specify London fork-block, overriding the bundled setting",
249
	}
250 251 252
	// Light server and client settings
	LightServeFlag = cli.IntFlag{
		Name:  "light.serve",
253
		Usage: "Maximum percentage of time allowed for serving LES requests (multi-threaded processing allows values over 100)",
254
		Value: ethconfig.Defaults.LightServ,
255
	}
256 257 258
	LightIngressFlag = cli.IntFlag{
		Name:  "light.ingress",
		Usage: "Incoming bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)",
259
		Value: ethconfig.Defaults.LightIngress,
260
	}
261 262 263
	LightEgressFlag = cli.IntFlag{
		Name:  "light.egress",
		Usage: "Outgoing bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)",
264
		Value: ethconfig.Defaults.LightEgress,
265
	}
266 267 268
	LightMaxPeersFlag = cli.IntFlag{
		Name:  "light.maxpeers",
		Usage: "Maximum number of light clients to serve, or light servers to attach to",
269
		Value: ethconfig.Defaults.LightPeers,
270
	}
271 272 273
	UltraLightServersFlag = cli.StringFlag{
		Name:  "ulc.servers",
		Usage: "List of trusted ultra-light servers",
274
		Value: strings.Join(ethconfig.Defaults.UltraLightServers, ","),
275
	}
276 277 278
	UltraLightFractionFlag = cli.IntFlag{
		Name:  "ulc.fraction",
		Usage: "Minimum % of trusted ultra-light servers required to announce a new head",
279
		Value: ethconfig.Defaults.UltraLightFraction,
280 281 282 283
	}
	UltraLightOnlyAnnounceFlag = cli.BoolFlag{
		Name:  "ulc.onlyannounce",
		Usage: "Ultra light server sends announcements only",
284
	}
285 286 287 288
	LightNoPruneFlag = cli.BoolFlag{
		Name:  "light.nopruning",
		Usage: "Disable ancient light chain data pruning",
	}
289 290 291 292
	LightNoSyncServeFlag = cli.BoolFlag{
		Name:  "light.nosyncserve",
		Usage: "Enables serving light clients before syncing",
	}
293 294 295 296 297 298 299 300
	// 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)",
301
		Value: ethconfig.Defaults.Ethash.CachesInMem,
302 303 304 305
	}
	EthashCachesOnDiskFlag = cli.IntFlag{
		Name:  "ethash.cachesondisk",
		Usage: "Number of recent ethash caches to keep on disk (16MB each)",
306
		Value: ethconfig.Defaults.Ethash.CachesOnDisk,
307
	}
308 309 310 311
	EthashCachesLockMmapFlag = cli.BoolFlag{
		Name:  "ethash.cacheslockmmap",
		Usage: "Lock memory maps of recent ethash caches",
	}
312 313
	EthashDatasetDirFlag = DirectoryFlag{
		Name:  "ethash.dagdir",
314
		Usage: "Directory to store the ethash mining DAGs",
315
		Value: DirectoryString(ethconfig.Defaults.Ethash.DatasetDir),
316 317 318 319
	}
	EthashDatasetsInMemoryFlag = cli.IntFlag{
		Name:  "ethash.dagsinmem",
		Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
320
		Value: ethconfig.Defaults.Ethash.DatasetsInMem,
321 322 323 324
	}
	EthashDatasetsOnDiskFlag = cli.IntFlag{
		Name:  "ethash.dagsondisk",
		Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
325
		Value: ethconfig.Defaults.Ethash.DatasetsOnDisk,
326
	}
327 328 329 330
	EthashDatasetsLockMmapFlag = cli.BoolFlag{
		Name:  "ethash.dagslockmmap",
		Usage: "Lock memory maps for recent ethash mining DAGs",
	}
331
	// Transaction pool settings
332 333 334 335
	TxPoolLocalsFlag = cli.StringFlag{
		Name:  "txpool.locals",
		Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)",
	}
336 337 338 339
	TxPoolNoLocalsFlag = cli.BoolFlag{
		Name:  "txpool.nolocals",
		Usage: "Disables price exemptions for locally submitted transactions",
	}
340 341 342 343 344 345 346 347 348 349
	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,
	}
350 351 352
	TxPoolPriceLimitFlag = cli.Uint64Flag{
		Name:  "txpool.pricelimit",
		Usage: "Minimum gas price limit to enforce for acceptance into the pool",
353
		Value: ethconfig.Defaults.TxPool.PriceLimit,
354 355 356 357
	}
	TxPoolPriceBumpFlag = cli.Uint64Flag{
		Name:  "txpool.pricebump",
		Usage: "Price bump percentage to replace an already existing transaction",
358
		Value: ethconfig.Defaults.TxPool.PriceBump,
359 360 361 362
	}
	TxPoolAccountSlotsFlag = cli.Uint64Flag{
		Name:  "txpool.accountslots",
		Usage: "Minimum number of executable transaction slots guaranteed per account",
363
		Value: ethconfig.Defaults.TxPool.AccountSlots,
364 365 366 367
	}
	TxPoolGlobalSlotsFlag = cli.Uint64Flag{
		Name:  "txpool.globalslots",
		Usage: "Maximum number of executable transaction slots for all accounts",
368
		Value: ethconfig.Defaults.TxPool.GlobalSlots,
369 370 371 372
	}
	TxPoolAccountQueueFlag = cli.Uint64Flag{
		Name:  "txpool.accountqueue",
		Usage: "Maximum number of non-executable transaction slots permitted per account",
373
		Value: ethconfig.Defaults.TxPool.AccountQueue,
374 375 376 377
	}
	TxPoolGlobalQueueFlag = cli.Uint64Flag{
		Name:  "txpool.globalqueue",
		Usage: "Maximum number of non-executable transaction slots for all accounts",
378
		Value: ethconfig.Defaults.TxPool.GlobalQueue,
379 380 381 382
	}
	TxPoolLifetimeFlag = cli.DurationFlag{
		Name:  "txpool.lifetime",
		Usage: "Maximum amount of time non-executable transaction are queued",
383
		Value: ethconfig.Defaults.TxPool.Lifetime,
384
	}
385 386 387
	// Performance tuning settings
	CacheFlag = cli.IntFlag{
		Name:  "cache",
388
		Usage: "Megabytes of memory allocated to internal caching (default = 4096 mainnet full node, 128 light mode)",
389 390 391 392 393
		Value: 1024,
	}
	CacheDatabaseFlag = cli.IntFlag{
		Name:  "cache.database",
		Usage: "Percentage of cache memory allowance to use for database io",
394 395 396 397
		Value: 50,
	}
	CacheTrieFlag = cli.IntFlag{
		Name:  "cache.trie",
398 399
		Usage: "Percentage of cache memory allowance to use for trie caching (default = 15% full mode, 30% archive mode)",
		Value: 15,
400
	}
401 402 403
	CacheTrieJournalFlag = cli.StringFlag{
		Name:  "cache.trie.journal",
		Usage: "Disk journal directory for trie cache to survive node restarts",
404
		Value: ethconfig.Defaults.TrieCleanCacheJournal,
405 406 407 408
	}
	CacheTrieRejournalFlag = cli.DurationFlag{
		Name:  "cache.trie.rejournal",
		Usage: "Time interval to regenerate the trie cache journal",
409
		Value: ethconfig.Defaults.TrieCleanCacheRejournal,
410
	}
411 412
	CacheGCFlag = cli.IntFlag{
		Name:  "cache.gc",
413
		Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)",
414
		Value: 25,
415
	}
416 417 418 419 420
	CacheSnapshotFlag = cli.IntFlag{
		Name:  "cache.snapshot",
		Usage: "Percentage of cache memory allowance to use for snapshot caching (default = 10% full mode, 20% archive mode)",
		Value: 10,
	}
421 422 423 424
	CacheNoPrefetchFlag = cli.BoolFlag{
		Name:  "cache.noprefetch",
		Usage: "Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data)",
	}
425
	CachePreimagesFlag = cli.BoolFlag{
426
		Name:  "cache.preimages",
427
		Usage: "Enable recording the SHA3/keccak preimages of trie keys",
428
	}
429 430 431 432
	// Miner settings
	MiningEnabledFlag = cli.BoolFlag{
		Name:  "mine",
		Usage: "Enable mining",
433
	}
434
	MinerThreadsFlag = cli.IntFlag{
435
		Name:  "miner.threads",
436
		Usage: "Number of CPU threads to use for mining",
437 438 439 440 441
		Value: 0,
	}
	MinerNotifyFlag = cli.StringFlag{
		Name:  "miner.notify",
		Usage: "Comma separated HTTP URL list to notify of new work packages",
442
	}
443 444 445 446
	MinerNotifyFullFlag = cli.BoolFlag{
		Name:  "miner.notify.full",
		Usage: "Notify with pending block headers instead of work packages",
	}
447 448 449
	MinerGasLimitFlag = cli.Uint64Flag{
		Name:  "miner.gaslimit",
		Usage: "Target gas ceiling for mined blocks",
450
		Value: ethconfig.Defaults.Miner.GasCeil,
451
	}
452 453
	MinerGasPriceFlag = BigFlag{
		Name:  "miner.gasprice",
454
		Usage: "Minimum gas price for mining a transaction",
455
		Value: ethconfig.Defaults.Miner.GasPrice,
Z
zelig 已提交
456
	}
457 458 459 460 461 462 463
	MinerEtherbaseFlag = cli.StringFlag{
		Name:  "miner.etherbase",
		Usage: "Public address for block mining rewards (default = first account)",
		Value: "0",
	}
	MinerExtraDataFlag = cli.StringFlag{
		Name:  "miner.extradata",
464
		Usage: "Block extra data set by the miner (default = client version)",
Z
zelig 已提交
465
	}
466 467
	MinerRecommitIntervalFlag = cli.DurationFlag{
		Name:  "miner.recommit",
468
		Usage: "Time interval to recreate the block being mined",
469
		Value: ethconfig.Defaults.Miner.Recommit,
470
	}
471 472 473 474
	MinerNoVerfiyFlag = cli.BoolFlag{
		Name:  "miner.noverify",
		Usage: "Disable remote sealing verification",
	}
475
	// Account settings
Z
zelig 已提交
476 477
	UnlockedAccountFlag = cli.StringFlag{
		Name:  "unlock",
478
		Usage: "Comma separated list of accounts to unlock",
Z
zelig 已提交
479 480 481 482
		Value: "",
	}
	PasswordFileFlag = cli.StringFlag{
		Name:  "password",
A
ayeowch 已提交
483
		Usage: "Password file to use for non-interactive password input",
Z
zelig 已提交
484
		Value: "",
Z
zelig 已提交
485
	}
486 487 488 489 490
	ExternalSignerFlag = cli.StringFlag{
		Name:  "signer",
		Usage: "External signer (url or path to ipc file)",
		Value: "",
	}
491 492 493 494
	VMEnableDebugFlag = cli.BoolFlag{
		Name:  "vmdebug",
		Usage: "Record information useful for VM and contract debugging",
	}
495 496 497 498
	InsecureUnlockAllowedFlag = cli.BoolFlag{
		Name:  "allow-insecure-unlock",
		Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http",
	}
499
	RPCGlobalGasCapFlag = cli.Uint64Flag{
500
		Name:  "rpc.gascap",
501
		Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)",
502
		Value: ethconfig.Defaults.RPCGasCap,
503
	}
504
	RPCGlobalTxFeeCapFlag = cli.Float64Flag{
505 506
		Name:  "rpc.txfeecap",
		Usage: "Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)",
507
		Value: ethconfig.Defaults.RPCTxFeeCap,
508
	}
509 510 511 512 513
	// Logging and debug settings
	EthStatsURLFlag = cli.StringFlag{
		Name:  "ethstats",
		Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)",
	}
514 515 516 517
	FakePoWFlag = cli.BoolFlag{
		Name:  "fakepow",
		Usage: "Disables proof-of-work verification",
	}
518 519 520 521
	NoCompactionFlag = cli.BoolFlag{
		Name:  "nocompaction",
		Usage: "Disables db compaction after import",
	}
522
	// RPC settings
523 524 525 526 527 528 529 530
	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)",
	}
531 532
	HTTPEnabledFlag = cli.BoolFlag{
		Name:  "http",
533
		Usage: "Enable the HTTP-RPC server",
534
	}
535 536
	HTTPListenAddrFlag = cli.StringFlag{
		Name:  "http.addr",
537
		Usage: "HTTP-RPC server listening interface",
538
		Value: node.DefaultHTTPHost,
539
	}
540 541
	HTTPPortFlag = cli.IntFlag{
		Name:  "http.port",
542
		Usage: "HTTP-RPC server listening port",
543
		Value: node.DefaultHTTPPort,
544
	}
545 546
	HTTPCORSDomainFlag = cli.StringFlag{
		Name:  "http.corsdomain",
547
		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
548 549
		Value: "",
	}
550 551
	HTTPVirtualHostsFlag = cli.StringFlag{
		Name:  "http.vhosts",
552
		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
553
		Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
554
	}
555 556
	HTTPApiFlag = cli.StringFlag{
		Name:  "http.api",
557
		Usage: "API's offered over the HTTP-RPC interface",
558
		Value: "",
559
	}
560 561 562 563 564
	HTTPPathPrefixFlag = cli.StringFlag{
		Name:  "http.rpcprefix",
		Usage: "HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.",
		Value: "",
	}
R
rene 已提交
565 566 567 568 569 570 571 572 573 574 575 576 577 578
	GraphQLEnabledFlag = cli.BoolFlag{
		Name:  "graphql",
		Usage: "Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.",
	}
	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, ","),
	}
579
	WSEnabledFlag = cli.BoolFlag{
580
		Name:  "ws",
581 582 583
		Usage: "Enable the WS-RPC server",
	}
	WSListenAddrFlag = cli.StringFlag{
584
		Name:  "ws.addr",
585
		Usage: "WS-RPC server listening interface",
586
		Value: node.DefaultWSHost,
587 588
	}
	WSPortFlag = cli.IntFlag{
589
		Name:  "ws.port",
590
		Usage: "WS-RPC server listening port",
591
		Value: node.DefaultWSPort,
592 593
	}
	WSApiFlag = cli.StringFlag{
594
		Name:  "ws.api",
595
		Usage: "API's offered over the WS-RPC interface",
596
		Value: "",
597
	}
B
Bas van Kervel 已提交
598
	WSAllowedOriginsFlag = cli.StringFlag{
599
		Name:  "ws.origins",
B
Bas van Kervel 已提交
600
		Usage: "Origins from which to accept websockets requests",
601
		Value: "",
602
	}
603 604 605 606 607
	WSPathPrefixFlag = cli.StringFlag{
		Name:  "ws.rpcprefix",
		Usage: "HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.",
		Value: "",
	}
608 609
	ExecFlag = cli.StringFlag{
		Name:  "exec",
610
		Usage: "Execute JavaScript statement",
611
	}
612
	PreloadJSFlag = cli.StringFlag{
613 614 615
		Name:  "preload",
		Usage: "Comma separated list of JavaScript files to preload into the console",
	}
616 617 618 619
	AllowUnprotectedTxs = cli.BoolFlag{
		Name:  "rpc.allow-unprotected-txs",
		Usage: "Allow for unprotected (non EIP155 signed) transactions to be submitted via RPC",
	}
620

621 622 623
	// Network Settings
	MaxPeersFlag = cli.IntFlag{
		Name:  "maxpeers",
624
		Usage: "Maximum number of network peers (network disabled if set to 0)",
625
		Value: node.DefaultConfig.P2P.MaxPeers,
626
	}
627 628 629
	MaxPendingPeersFlag = cli.IntFlag{
		Name:  "maxpendpeers",
		Usage: "Maximum number of pending connection attempts (defaults used if set to 0)",
630
		Value: node.DefaultConfig.P2P.MaxPendingPeers,
631
	}
632 633 634 635 636
	ListenPortFlag = cli.IntFlag{
		Name:  "port",
		Usage: "Network listening port",
		Value: 30303,
	}
637
	BootnodesFlag = cli.StringFlag{
638
		Name:  "bootnodes",
639
		Usage: "Comma separated enode URLs for P2P discovery bootstrap",
640
		Value: "",
641 642 643 644 645 646 647 648 649 650 651
	}
	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",
652
		Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
653 654
		Value: "any",
	}
655 656 657 658
	NoDiscoverFlag = cli.BoolFlag{
		Name:  "nodiscover",
		Usage: "Disables the peer discovery mechanism (manual peer addition)",
	}
659 660 661 662
	DiscoveryV5Flag = cli.BoolFlag{
		Name:  "v5disc",
		Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
	}
663 664 665 666
	NetrestrictFlag = cli.StringFlag{
		Name:  "netrestrict",
		Usage: "Restricts network communication to the given IP networks (CIDR masks)",
	}
667 668 669 670
	DNSDiscoveryFlag = cli.StringFlag{
		Name:  "discovery.dns",
		Usage: "Sets DNS discovery entry points (use \"\" to disable DNS)",
	}
671

672
	// ATM the url is left to the user and deployment to
673
	JSpathFlag = DirectoryFlag{
Z
CLI:  
zelig 已提交
674
		Name:  "jspath",
675
		Usage: "JavaScript root path for `loadScript`",
676
		Value: DirectoryString("."),
Z
CLI:  
zelig 已提交
677
	}
678 679

	// Gas price oracle settings
680
	GpoBlocksFlag = cli.IntFlag{
681
		Name:  "gpo.blocks",
682
		Usage: "Number of recent blocks to check for gas prices",
683
		Value: ethconfig.Defaults.GPO.Blocks,
Z
zsfelfoldi 已提交
684
	}
685
	GpoPercentileFlag = cli.IntFlag{
686
		Name:  "gpo.percentile",
687
		Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices",
688
		Value: ethconfig.Defaults.GPO.Percentile,
Z
zsfelfoldi 已提交
689
	}
690 691 692
	GpoMaxGasPriceFlag = cli.Int64Flag{
		Name:  "gpo.maxprice",
		Usage: "Maximum gas price will be recommended by gpo",
693
		Value: ethconfig.Defaults.GPO.MaxPrice.Int64(),
694
	}
695 696 697 698 699
	GpoIgnoreGasPriceFlag = cli.Int64Flag{
		Name:  "gpo.ignoreprice",
		Usage: "Gas price below which gpo will ignore transactions",
		Value: ethconfig.Defaults.GPO.IgnorePrice.Int64(),
	}
700 701 702

	// Metrics flags
	MetricsEnabledFlag = cli.BoolFlag{
703
		Name:  "metrics",
704 705
		Usage: "Enable metrics collection and reporting",
	}
706 707 708 709
	MetricsEnabledExpensiveFlag = cli.BoolFlag{
		Name:  "metrics.expensive",
		Usage: "Enable expensive metrics collection and reporting",
	}
710 711 712 713 714 715 716 717

	// MetricsHTTPFlag defines the endpoint for a stand-alone metrics HTTP endpoint.
	// Since the pprof service enables sensitive/vulnerable behavior, this allows a user
	// to enable a public-OK metrics endpoint without having to worry about ALSO exposing
	// other profiling behavior or information.
	MetricsHTTPFlag = cli.StringFlag{
		Name:  "metrics.addr",
		Usage: "Enable stand-alone metrics HTTP server listening interface",
718
		Value: metrics.DefaultConfig.HTTP,
719 720 721 722
	}
	MetricsPortFlag = cli.IntFlag{
		Name:  "metrics.port",
		Usage: "Metrics HTTP server listening port",
723
		Value: metrics.DefaultConfig.Port,
724
	}
725 726 727 728 729 730 731
	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",
732
		Value: metrics.DefaultConfig.InfluxDBEndpoint,
733 734 735 736
	}
	MetricsInfluxDBDatabaseFlag = cli.StringFlag{
		Name:  "metrics.influxdb.database",
		Usage: "InfluxDB database name to push reported metrics to",
737
		Value: metrics.DefaultConfig.InfluxDBDatabase,
738 739 740 741
	}
	MetricsInfluxDBUsernameFlag = cli.StringFlag{
		Name:  "metrics.influxdb.username",
		Usage: "Username to authorize access to the database",
742
		Value: metrics.DefaultConfig.InfluxDBUsername,
743 744 745 746
	}
	MetricsInfluxDBPasswordFlag = cli.StringFlag{
		Name:  "metrics.influxdb.password",
		Usage: "Password to authorize access to the database",
747
		Value: metrics.DefaultConfig.InfluxDBPassword,
748
	}
749 750 751
	// 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.
752
	// https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key
753 754 755
	MetricsInfluxDBTagsFlag = cli.StringFlag{
		Name:  "metrics.influxdb.tags",
		Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements",
756
		Value: metrics.DefaultConfig.InfluxDBTags,
757
	}
758 759 760 761 762

	CatalystFlag = cli.BoolFlag{
		Name:  "catalyst",
		Usage: "Catalyst mode (eth2 integration testing)",
	}
763 764
)

765
// MakeDataDir retrieves the currently requested data directory, terminating
766
// if none (or the empty string) is specified. If the node is starting a testnet,
767
// then a subdirectory of the specified datadir will be used.
768
func MakeDataDir(ctx *cli.Context) string {
769
	if path := ctx.GlobalString(DataDirFlag.Name); path != "" {
770
		if ctx.GlobalBool(RopstenFlag.Name) {
771 772 773
			// Maintain compatibility with older Geth configurations storing the
			// Ropsten database in `testnet` instead of `ropsten`.
			return filepath.Join(path, "ropsten")
774
		}
775 776 777
		if ctx.GlobalBool(RinkebyFlag.Name) {
			return filepath.Join(path, "rinkeby")
		}
778 779 780
		if ctx.GlobalBool(GoerliFlag.Name) {
			return filepath.Join(path, "goerli")
		}
781 782
		if ctx.GlobalBool(CalaverasFlag.Name) {
			return filepath.Join(path, "calaveras")
783
		}
784
		return path
785
	}
786
	Fatalf("Cannot determine default data directory, please set manually (--datadir)")
787
	return ""
788 789
}

790
// setNodeKey creates a node key from set command line flags, either loading it
791 792
// 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.
793
func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
794 795 796
	var (
		hex  = ctx.GlobalString(NodeKeyHexFlag.Name)
		file = ctx.GlobalString(NodeKeyFileFlag.Name)
797 798
		key  *ecdsa.PrivateKey
		err  error
799
	)
800 801
	switch {
	case file != "" && hex != "":
802
		Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name)
803 804
	case file != "":
		if key, err = crypto.LoadECDSA(file); err != nil {
805
			Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err)
806
		}
807
		cfg.PrivateKey = key
808 809
	case hex != "":
		if key, err = crypto.HexToECDSA(hex); err != nil {
810
			Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err)
811
		}
812
		cfg.PrivateKey = key
813 814 815
	}
}

816 817
// setNodeUserIdent creates the user identifier from CLI flags.
func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
818
	if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 {
819
		cfg.UserIdent = identity
820 821 822
	}
}

823
// setBootstrapNodes creates a list of bootstrap nodes from the command line
824
// flags, reverting to pre-configured ones if none have been specified.
825
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
826
	urls := params.MainnetBootnodes
827
	switch {
828 829 830
	case ctx.GlobalIsSet(BootnodesFlag.Name):
		urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name))
	case ctx.GlobalBool(RopstenFlag.Name):
831
		urls = params.RopstenBootnodes
832 833
	case ctx.GlobalBool(RinkebyFlag.Name):
		urls = params.RinkebyBootnodes
834 835
	case ctx.GlobalBool(GoerliFlag.Name):
		urls = params.GoerliBootnodes
836 837
	case ctx.GlobalBool(CalaverasFlag.Name):
		urls = params.CalaverasBootnodes
838 839
	case cfg.BootstrapNodes != nil:
		return // already set, don't apply defaults.
840 841
	}

842
	cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls))
843
	for _, url := range urls {
844
		if url != "" {
845
			node, err := enode.Parse(enode.ValidSchemes, url)
846 847
			if err != nil {
				log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
848
				continue
849 850
			}
			cfg.BootstrapNodes = append(cfg.BootstrapNodes, node)
851 852 853 854
		}
	}
}

855
// setBootstrapNodesV5 creates a list of bootstrap nodes from the command line
856
// flags, reverting to pre-configured ones if none have been specified.
857
func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
858
	urls := params.V5Bootnodes
859
	switch {
860 861
	case ctx.GlobalIsSet(BootnodesFlag.Name):
		urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name))
862
	case cfg.BootstrapNodesV5 != nil:
863
		return // already set, don't apply defaults.
864 865
	}

866
	cfg.BootstrapNodesV5 = make([]*enode.Node, 0, len(urls))
867
	for _, url := range urls {
868
		if url != "" {
869
			node, err := enode.Parse(enode.ValidSchemes, url)
870 871 872 873 874
			if err != nil {
				log.Error("Bootstrap URL invalid", "enode", url, "err", err)
				continue
			}
			cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node)
875 876 877 878
		}
	}
}

879
// setListenAddress creates a TCP listening address string from set command
880
// line flags.
881 882 883 884
func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
	if ctx.GlobalIsSet(ListenPortFlag.Name) {
		cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
	}
885 886
}

887 888 889 890 891 892 893 894
// 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
895 896 897
	}
}

898
// SplitAndTrim splits input separated by a comma
899
// and trims excessive white space from the substrings.
900
func SplitAndTrim(input string) (ret []string) {
901 902
	l := strings.Split(input, ",")
	for _, r := range l {
903
		if r = strings.TrimSpace(r); r != "" {
904 905
			ret = append(ret, r)
		}
906
	}
907
	return ret
908 909
}

910
// setHTTP creates the HTTP RPC listener interface string from the set
911
// command line flags, returning empty if the HTTP endpoint is disabled.
912
func setHTTP(ctx *cli.Context, cfg *node.Config) {
913
	if ctx.GlobalBool(LegacyRPCEnabledFlag.Name) && cfg.HTTPHost == "" {
914
		log.Warn("The flag --rpc is deprecated and will be removed June 2021, please use --http")
915
		cfg.HTTPHost = "127.0.0.1"
916 917
		if ctx.GlobalIsSet(LegacyRPCListenAddrFlag.Name) {
			cfg.HTTPHost = ctx.GlobalString(LegacyRPCListenAddrFlag.Name)
918
			log.Warn("The flag --rpcaddr is deprecated and will be removed June 2021, please use --http.addr")
919 920
		}
	}
921 922 923 924 925
	if ctx.GlobalBool(HTTPEnabledFlag.Name) && cfg.HTTPHost == "" {
		cfg.HTTPHost = "127.0.0.1"
		if ctx.GlobalIsSet(HTTPListenAddrFlag.Name) {
			cfg.HTTPHost = ctx.GlobalString(HTTPListenAddrFlag.Name)
		}
926
	}
927 928 929

	if ctx.GlobalIsSet(LegacyRPCPortFlag.Name) {
		cfg.HTTPPort = ctx.GlobalInt(LegacyRPCPortFlag.Name)
930
		log.Warn("The flag --rpcport is deprecated and will be removed June 2021, please use --http.port")
931
	}
932 933
	if ctx.GlobalIsSet(HTTPPortFlag.Name) {
		cfg.HTTPPort = ctx.GlobalInt(HTTPPortFlag.Name)
934
	}
935 936

	if ctx.GlobalIsSet(LegacyRPCCORSDomainFlag.Name) {
937
		cfg.HTTPCors = SplitAndTrim(ctx.GlobalString(LegacyRPCCORSDomainFlag.Name))
938
		log.Warn("The flag --rpccorsdomain is deprecated and will be removed June 2021, please use --http.corsdomain")
939 940
	}
	if ctx.GlobalIsSet(HTTPCORSDomainFlag.Name) {
941
		cfg.HTTPCors = SplitAndTrim(ctx.GlobalString(HTTPCORSDomainFlag.Name))
942 943 944
	}

	if ctx.GlobalIsSet(LegacyRPCApiFlag.Name) {
945
		cfg.HTTPModules = SplitAndTrim(ctx.GlobalString(LegacyRPCApiFlag.Name))
946
		log.Warn("The flag --rpcapi is deprecated and will be removed June 2021, please use --http.api")
947 948
	}
	if ctx.GlobalIsSet(HTTPApiFlag.Name) {
949
		cfg.HTTPModules = SplitAndTrim(ctx.GlobalString(HTTPApiFlag.Name))
950 951 952
	}

	if ctx.GlobalIsSet(LegacyRPCVirtualHostsFlag.Name) {
953
		cfg.HTTPVirtualHosts = SplitAndTrim(ctx.GlobalString(LegacyRPCVirtualHostsFlag.Name))
954
		log.Warn("The flag --rpcvhosts is deprecated and will be removed June 2021, please use --http.vhosts")
955 956
	}
	if ctx.GlobalIsSet(HTTPVirtualHostsFlag.Name) {
957
		cfg.HTTPVirtualHosts = SplitAndTrim(ctx.GlobalString(HTTPVirtualHostsFlag.Name))
958
	}
959 960 961 962

	if ctx.GlobalIsSet(HTTPPathPrefixFlag.Name) {
		cfg.HTTPPathPrefix = ctx.GlobalString(HTTPPathPrefixFlag.Name)
	}
963 964 965
	if ctx.GlobalIsSet(AllowUnprotectedTxs.Name) {
		cfg.AllowUnprotectedTxs = ctx.GlobalBool(AllowUnprotectedTxs.Name)
	}
966 967
}

968 969 970 971
// 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.GlobalIsSet(GraphQLCORSDomainFlag.Name) {
972
		cfg.GraphQLCors = SplitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name))
973 974
	}
	if ctx.GlobalIsSet(GraphQLVirtualHostsFlag.Name) {
975
		cfg.GraphQLVirtualHosts = SplitAndTrim(ctx.GlobalString(GraphQLVirtualHostsFlag.Name))
976 977 978
	}
}

979
// setWS creates the WebSocket RPC listener interface string from the set
980
// command line flags, returning empty if the HTTP endpoint is disabled.
981 982 983 984 985 986 987 988 989 990
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)
	}
991

992
	if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) {
993
		cfg.WSOrigins = SplitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name))
994
	}
995

996
	if ctx.GlobalIsSet(WSApiFlag.Name) {
997
		cfg.WSModules = SplitAndTrim(ctx.GlobalString(WSApiFlag.Name))
998
	}
999 1000 1001 1002

	if ctx.GlobalIsSet(WSPathPrefixFlag.Name) {
		cfg.WSPathPrefix = ctx.GlobalString(WSPathPrefixFlag.Name)
	}
1003 1004 1005 1006 1007
}

// 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) {
1008
	CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag)
1009 1010 1011 1012 1013
	switch {
	case ctx.GlobalBool(IPCDisabledFlag.Name):
		cfg.IPCPath = ""
	case ctx.GlobalIsSet(IPCPathFlag.Name):
		cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name)
1014 1015 1016
	}
}

1017
// setLes configures the les server and ultra light client settings from the command line flags.
1018
func setLes(ctx *cli.Context, cfg *ethconfig.Config) {
1019 1020 1021 1022 1023
	if ctx.GlobalIsSet(LightServeFlag.Name) {
		cfg.LightServ = ctx.GlobalInt(LightServeFlag.Name)
	}
	if ctx.GlobalIsSet(LightIngressFlag.Name) {
		cfg.LightIngress = ctx.GlobalInt(LightIngressFlag.Name)
1024
	}
1025 1026
	if ctx.GlobalIsSet(LightEgressFlag.Name) {
		cfg.LightEgress = ctx.GlobalInt(LightEgressFlag.Name)
1027
	}
1028 1029
	if ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
		cfg.LightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name)
1030
	}
1031 1032
	if ctx.GlobalIsSet(UltraLightServersFlag.Name) {
		cfg.UltraLightServers = strings.Split(ctx.GlobalString(UltraLightServersFlag.Name), ",")
1033
	}
1034 1035
	if ctx.GlobalIsSet(UltraLightFractionFlag.Name) {
		cfg.UltraLightFraction = ctx.GlobalInt(UltraLightFractionFlag.Name)
1036
	}
1037
	if cfg.UltraLightFraction <= 0 && cfg.UltraLightFraction > 100 {
1038 1039
		log.Error("Ultra light fraction is invalid", "had", cfg.UltraLightFraction, "updated", ethconfig.Defaults.UltraLightFraction)
		cfg.UltraLightFraction = ethconfig.Defaults.UltraLightFraction
1040
	}
1041 1042
	if ctx.GlobalIsSet(UltraLightOnlyAnnounceFlag.Name) {
		cfg.UltraLightOnlyAnnounce = ctx.GlobalBool(UltraLightOnlyAnnounceFlag.Name)
1043
	}
1044 1045 1046
	if ctx.GlobalIsSet(LightNoPruneFlag.Name) {
		cfg.LightNoPrune = ctx.GlobalBool(LightNoPruneFlag.Name)
	}
1047 1048 1049
	if ctx.GlobalIsSet(LightNoSyncServeFlag.Name) {
		cfg.LightNoSyncServe = ctx.GlobalBool(LightNoSyncServeFlag.Name)
	}
1050 1051
}

1052
// MakeDatabaseHandles raises out the number of allowed file handles per process
1053
// for Geth and returns half of the allowance to assign to the database.
1054
func MakeDatabaseHandles() int {
1055
	limit, err := fdlimit.Maximum()
1056
	if err != nil {
1057
		Fatalf("Failed to retrieve file descriptor allowance: %v", err)
1058
	}
1059 1060
	raised, err := fdlimit.Raise(uint64(limit))
	if err != nil {
1061
		Fatalf("Failed to raise file descriptor allowance: %v", err)
1062
	}
1063
	return int(raised / 2) // Leave half for networking and other stuff
1064 1065
}

1066 1067
// MakeAddress converts an account specified directly as a hex encoded string or
// a key index in the key store to an internal account representation.
1068
func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
1069 1070
	// If the specified account is a valid address, return it
	if common.IsHexAddress(account) {
F
Felix Lange 已提交
1071
		return accounts.Account{Address: common.HexToAddress(account)}, nil
1072 1073 1074
	}
	// Otherwise try to interpret the account as a keystore index
	index, err := strconv.Atoi(account)
1075
	if err != nil || index < 0 {
F
Felix Lange 已提交
1076
		return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account)
1077
	}
1078 1079 1080 1081 1082 1083
	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("-------------------------------------------------------------------")

1084 1085 1086 1087 1088
	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
1089 1090
}

1091
// setEtherbase retrieves the etherbase either from the directly specified
1092
// command line flags or from the keystore if CLI indexed.
1093
func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *ethconfig.Config) {
1094
	// Extract the current etherbase
1095 1096 1097 1098 1099 1100
	var etherbase string
	if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) {
		etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name)
	}
	// Convert the etherbase into an address and configure it
	if etherbase != "" {
1101 1102 1103 1104 1105
		if ks != nil {
			account, err := MakeAddress(ks, etherbase)
			if err != nil {
				Fatalf("Invalid miner etherbase: %v", err)
			}
1106
			cfg.Miner.Etherbase = account.Address
1107 1108
		} else {
			Fatalf("No etherbase configured")
1109
		}
1110
	}
1111 1112
}

1113
// MakePasswordList reads password lines from the file specified by the global --password flag.
1114
func MakePasswordList(ctx *cli.Context) []string {
1115 1116 1117 1118 1119 1120
	path := ctx.GlobalString(PasswordFileFlag.Name)
	if path == "" {
		return nil
	}
	text, err := ioutil.ReadFile(path)
	if err != nil {
1121
		Fatalf("Failed to read password file: %v", err)
1122 1123 1124 1125 1126
	}
	lines := strings.Split(string(text), "\n")
	// Sanitise DOS line endings.
	for i := range lines {
		lines[i] = strings.TrimRight(lines[i], "\r")
1127
	}
1128
	return lines
1129 1130
}

1131 1132 1133 1134 1135 1136 1137
func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
	setNodeKey(ctx, cfg)
	setNAT(ctx, cfg)
	setListenAddress(ctx, cfg)
	setBootstrapNodes(ctx, cfg)
	setBootstrapNodesV5(ctx, cfg)

1138
	lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light"
1139
	lightServer := (ctx.GlobalInt(LightServeFlag.Name) != 0)
1140

1141 1142
	lightPeers := ctx.GlobalInt(LightMaxPeersFlag.Name)
	if lightClient && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
1143 1144 1145 1146
		// dynamic default - for clients we use 1/10th of the default for servers
		lightPeers /= 10
	}

1147 1148
	if ctx.GlobalIsSet(MaxPeersFlag.Name) {
		cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
1149
		if lightServer && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
1150 1151
			cfg.MaxPeers += lightPeers
		}
1152 1153 1154 1155
	} else {
		if lightServer {
			cfg.MaxPeers += lightPeers
		}
1156
		if lightClient && ctx.GlobalIsSet(LightMaxPeersFlag.Name) && cfg.MaxPeers < lightPeers {
1157 1158
			cfg.MaxPeers = lightPeers
		}
1159
	}
1160 1161 1162 1163 1164 1165 1166 1167 1168
	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)

1169 1170 1171
	if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) {
		cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name)
	}
1172
	if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient {
1173
		cfg.NoDiscovery = true
1174 1175
	}

1176 1177 1178
	// 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
1179
	forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name)
1180 1181 1182 1183
	if ctx.GlobalIsSet(DiscoveryV5Flag.Name) {
		cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name)
	} else if forceV5Discovery {
		cfg.DiscoveryV5 = true
1184
	}
1185

1186 1187 1188
	if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" {
		list, err := netutil.ParseNetlist(netrestrict)
		if err != nil {
1189
			Fatalf("Option %q: %v", NetrestrictFlag.Name, err)
1190
		}
1191
		cfg.NetRestrict = list
1192 1193
	}

1194
	if ctx.GlobalBool(DeveloperFlag.Name) || ctx.GlobalBool(CatalystFlag.Name) {
1195 1196
		// --dev mode can't use p2p networking.
		cfg.MaxPeers = 0
1197 1198
		cfg.ListenAddr = ""
		cfg.NoDial = true
1199 1200
		cfg.NoDiscovery = true
		cfg.DiscoveryV5 = false
1201 1202 1203
	}
}

1204 1205 1206 1207 1208
// 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)
1209
	setGraphQL(ctx, cfg)
1210 1211
	setWS(ctx, cfg)
	setNodeUserIdent(ctx, cfg)
1212
	setDataDir(ctx, cfg)
1213
	setSmartCard(ctx, cfg)
1214

1215 1216 1217 1218
	if ctx.GlobalIsSet(ExternalSignerFlag.Name) {
		cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name)
	}

1219 1220 1221
	if ctx.GlobalIsSet(KeyStoreDirFlag.Name) {
		cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name)
	}
1222 1223 1224
	if ctx.GlobalIsSet(DeveloperFlag.Name) {
		cfg.UseLightweightKDF = true
	}
1225 1226 1227
	if ctx.GlobalIsSet(LightKDFFlag.Name) {
		cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name)
	}
1228
	if ctx.GlobalIsSet(NoUSBFlag.Name) || cfg.NoUSB {
1229
		log.Warn("Option nousb is deprecated and USB is deactivated by default. Use --usb to enable")
1230
	}
1231 1232 1233
	if ctx.GlobalIsSet(USBFlag.Name) {
		cfg.USB = ctx.GlobalBool(USBFlag.Name)
	}
1234 1235 1236
	if ctx.GlobalIsSet(InsecureUnlockAllowedFlag.Name) {
		cfg.InsecureUnlockAllowed = ctx.GlobalBool(InsecureUnlockAllowedFlag.Name)
	}
1237 1238
}

1239 1240 1241 1242 1243 1244 1245 1246 1247
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 {
1248
		log.Info("Smartcard socket not found, disabling", "err", err)
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
		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
}

1259 1260 1261 1262 1263 1264
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
1265
	case ctx.GlobalBool(RopstenFlag.Name) && cfg.DataDir == node.DefaultDataDir():
1266 1267 1268 1269 1270 1271 1272 1273 1274
		// Maintain compatibility with older Geth configurations storing the
		// Ropsten database in `testnet` instead of `ropsten`.
		legacyPath := filepath.Join(node.DefaultDataDir(), "testnet")
		if _, err := os.Stat(legacyPath); !os.IsNotExist(err) {
			log.Warn("Using the deprecated `testnet` datadir. Future versions will store the Ropsten chain in `ropsten`.")
			cfg.DataDir = legacyPath
		} else {
			cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten")
		}
1275 1276

		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten")
1277
	case ctx.GlobalBool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir():
1278
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
1279
	case ctx.GlobalBool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
1280
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
1281 1282
	case ctx.GlobalBool(CalaverasFlag.Name) && cfg.DataDir == node.DefaultDataDir():
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "calaveras")
1283 1284 1285
	}
}

1286 1287 1288 1289
func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) {
	// If we are running the light client, apply another group
	// settings for gas oracle.
	if light {
1290
		*cfg = ethconfig.LightClientGPO
1291
	}
1292 1293 1294 1295 1296 1297
	if ctx.GlobalIsSet(GpoBlocksFlag.Name) {
		cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name)
	}
	if ctx.GlobalIsSet(GpoPercentileFlag.Name) {
		cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name)
	}
1298 1299 1300
	if ctx.GlobalIsSet(GpoMaxGasPriceFlag.Name) {
		cfg.MaxPrice = big.NewInt(ctx.GlobalInt64(GpoMaxGasPriceFlag.Name))
	}
1301 1302 1303
	if ctx.GlobalIsSet(GpoIgnoreGasPriceFlag.Name) {
		cfg.IgnorePrice = big.NewInt(ctx.GlobalInt64(GpoIgnoreGasPriceFlag.Name))
	}
1304 1305
}

1306
func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) {
1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
	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))
			}
		}
	}
1317 1318 1319
	if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) {
		cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name)
	}
1320 1321 1322 1323 1324 1325
	if ctx.GlobalIsSet(TxPoolJournalFlag.Name) {
		cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name)
	}
	if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) {
		cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name)
	}
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348
	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)
	}
}

1349
func setEthash(ctx *cli.Context, cfg *ethconfig.Config) {
1350
	if ctx.GlobalIsSet(EthashCacheDirFlag.Name) {
1351
		cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name)
1352 1353
	}
	if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) {
1354
		cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name)
1355 1356
	}
	if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) {
1357
		cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name)
1358 1359
	}
	if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) {
1360
		cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name)
1361
	}
1362 1363 1364
	if ctx.GlobalIsSet(EthashCachesLockMmapFlag.Name) {
		cfg.Ethash.CachesLockMmap = ctx.GlobalBool(EthashCachesLockMmapFlag.Name)
	}
1365
	if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) {
1366
		cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name)
1367 1368
	}
	if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) {
1369
		cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name)
1370
	}
1371 1372 1373
	if ctx.GlobalIsSet(EthashDatasetsLockMmapFlag.Name) {
		cfg.Ethash.DatasetsLockMmap = ctx.GlobalBool(EthashDatasetsLockMmapFlag.Name)
	}
1374 1375
}

1376 1377 1378 1379
func setMiner(ctx *cli.Context, cfg *miner.Config) {
	if ctx.GlobalIsSet(MinerNotifyFlag.Name) {
		cfg.Notify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",")
	}
1380
	cfg.NotifyFull = ctx.GlobalBool(MinerNotifyFullFlag.Name)
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390
	if ctx.GlobalIsSet(MinerExtraDataFlag.Name) {
		cfg.ExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name))
	}
	if ctx.GlobalIsSet(MinerGasLimitFlag.Name) {
		cfg.GasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name)
	}
	if ctx.GlobalIsSet(MinerGasPriceFlag.Name) {
		cfg.GasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name)
	}
	if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) {
1391
		cfg.Recommit = ctx.GlobalDuration(MinerRecommitIntervalFlag.Name)
1392 1393
	}
	if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) {
1394
		cfg.Noverify = ctx.GlobalBool(MinerNoVerfiyFlag.Name)
1395
	}
1396 1397 1398
	if ctx.GlobalIsSet(LegacyMinerGasTargetFlag.Name) {
		log.Warn("The generic --miner.gastarget flag is deprecated and will be removed in the future!")
	}
1399 1400
}

1401
func setWhitelist(ctx *cli.Context, cfg *ethconfig.Config) {
1402 1403 1404 1405 1406 1407 1408 1409 1410
	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)
1411
		}
1412 1413 1414 1415 1416 1417 1418 1419 1420
		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
1421 1422 1423
	}
}

1424
// CheckExclusive verifies that only a single instance of the provided flags was
1425 1426
// set by the user. Each flag might optionally be followed by a string type to
// specialize it further.
1427
func CheckExclusive(ctx *cli.Context, args ...interface{}) {
1428
	set := make([]string, 0, 1)
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
	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:
1441
				// Extended flag check, make sure value set doesn't conflict with passed in option
1442 1443
				if ctx.GlobalString(flag.GetName()) == option {
					name += "=" + option
1444
					set = append(set, "--"+name)
1445
				}
1446
				// shift arguments and continue
1447
				i++
1448
				continue
1449 1450 1451 1452 1453 1454 1455

			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
1456
		if ctx.GlobalIsSet(flag.GetName()) {
1457
			set = append(set, "--"+name)
1458 1459
		}
	}
1460
	if len(set) > 1 {
1461
		Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", "))
1462
	}
1463 1464 1465
}

// SetEthConfig applies eth-related command line flags to the config.
1466
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
1467
	// Avoid conflicting network flags
1468
	CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, CalaverasFlag)
1469
	CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light")
1470
	CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
1471 1472 1473 1474 1475
	if ctx.GlobalString(GCModeFlag.Name) == "archive" && ctx.GlobalUint64(TxLookupLimitFlag.Name) != 0 {
		ctx.GlobalSet(TxLookupLimitFlag.Name, "0")
		log.Warn("Disable transaction unindexing for archive node")
	}
	if ctx.GlobalIsSet(LightServeFlag.Name) && ctx.GlobalUint64(TxLookupLimitFlag.Name) != 0 {
1476 1477
		log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited")
	}
1478 1479 1480 1481
	var ks *keystore.KeyStore
	if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 {
		ks = keystores[0].(*keystore.KeyStore)
	}
1482
	setEtherbase(ctx, ks, cfg)
1483
	setGPO(ctx, &cfg.GPO, ctx.GlobalString(SyncModeFlag.Name) == "light")
1484
	setTxPool(ctx, &cfg.TxPool)
1485
	setEthash(ctx, cfg)
1486
	setMiner(ctx, &cfg.Miner)
1487
	setWhitelist(ctx, cfg)
1488
	setLes(ctx, cfg)
1489

1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509
	// Cap the cache allowance and tune the garbage collector
	mem, err := gopsutil.VirtualMemory()
	if err == nil {
		if 32<<(^uintptr(0)>>63) == 32 && mem.Total > 2*1024*1024*1024 {
			log.Warn("Lowering memory allowance on 32bit arch", "available", mem.Total/1024/1024, "addressable", 2*1024)
			mem.Total = 2 * 1024 * 1024 * 1024
		}
		allowance := int(mem.Total / 1024 / 1024 / 3)
		if cache := ctx.GlobalInt(CacheFlag.Name); cache > allowance {
			log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance)
			ctx.GlobalSet(CacheFlag.Name, strconv.Itoa(allowance))
		}
	}
	// Ensure Go's GC ignores the database cache for trigger percentage
	cache := ctx.GlobalInt(CacheFlag.Name)
	gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024)))

	log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc))
	godebug.SetGCPercent(int(gogc))

1510
	if ctx.GlobalIsSet(SyncModeFlag.Name) {
1511 1512 1513
		cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)
	}
	if ctx.GlobalIsSet(NetworkIdFlag.Name) {
1514
		cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name)
1515
	}
1516 1517
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) {
		cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
1518
	}
1519
	cfg.DatabaseHandles = MakeDatabaseHandles()
1520 1521 1522
	if ctx.GlobalIsSet(AncientFlag.Name) {
		cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name)
	}
1523

1524 1525 1526
	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
	}
1527 1528 1529 1530 1531 1532
	if ctx.GlobalIsSet(GCModeFlag.Name) {
		cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"
	}
	if ctx.GlobalIsSet(CacheNoPrefetchFlag.Name) {
		cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name)
	}
1533 1534 1535 1536 1537 1538
	// Read the value from the flag no matter if it's set or not.
	cfg.Preimages = ctx.GlobalBool(CachePreimagesFlag.Name)
	if cfg.NoPruning && !cfg.Preimages {
		cfg.Preimages = true
		log.Info("Enabling recording of key preimages since archive mode is used")
	}
1539 1540 1541
	if ctx.GlobalIsSet(TxLookupLimitFlag.Name) {
		cfg.TxLookupLimit = ctx.GlobalUint64(TxLookupLimitFlag.Name)
	}
1542 1543 1544
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
		cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
	}
1545 1546 1547 1548 1549 1550
	if ctx.GlobalIsSet(CacheTrieJournalFlag.Name) {
		cfg.TrieCleanCacheJournal = ctx.GlobalString(CacheTrieJournalFlag.Name)
	}
	if ctx.GlobalIsSet(CacheTrieRejournalFlag.Name) {
		cfg.TrieCleanCacheRejournal = ctx.GlobalDuration(CacheTrieRejournalFlag.Name)
	}
1551
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
1552
		cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
1553
	}
1554 1555 1556
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) {
		cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100
	}
1557
	if !ctx.GlobalBool(SnapshotFlag.Name) {
1558 1559 1560 1561 1562 1563 1564
		// If snap-sync is requested, this flag is also required
		if cfg.SyncMode == downloader.SnapSync {
			log.Info("Snap sync requested, enabling --snapshot")
		} else {
			cfg.TrieCleanCache += cfg.SnapshotCache
			cfg.SnapshotCache = 0 // Disabled
		}
1565
	}
1566 1567 1568 1569 1570 1571 1572
	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)
	}
1573

1574 1575
	if ctx.GlobalIsSet(RPCGlobalGasCapFlag.Name) {
		cfg.RPCGasCap = ctx.GlobalUint64(RPCGlobalGasCapFlag.Name)
1576 1577 1578 1579 1580
	}
	if cfg.RPCGasCap != 0 {
		log.Info("Set global gas cap", "cap", cfg.RPCGasCap)
	} else {
		log.Info("Global gas cap disabled")
1581
	}
1582 1583
	if ctx.GlobalIsSet(RPCGlobalTxFeeCapFlag.Name) {
		cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCapFlag.Name)
1584
	}
1585
	if ctx.GlobalIsSet(NoDiscoverFlag.Name) {
1586
		cfg.EthDiscoveryURLs, cfg.SnapDiscoveryURLs = []string{}, []string{}
1587
	} else if ctx.GlobalIsSet(DNSDiscoveryFlag.Name) {
1588 1589
		urls := ctx.GlobalString(DNSDiscoveryFlag.Name)
		if urls == "" {
1590
			cfg.EthDiscoveryURLs = []string{}
1591
		} else {
1592
			cfg.EthDiscoveryURLs = SplitAndTrim(urls)
1593 1594
		}
	}
1595
	// Override any default configs for hard coded networks.
1596
	switch {
1597 1598 1599 1600 1601 1602
	case ctx.GlobalBool(MainnetFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 1
		}
		cfg.Genesis = core.DefaultGenesisBlock()
		SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
1603
	case ctx.GlobalBool(RopstenFlag.Name):
1604
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
1605
			cfg.NetworkId = 3
1606
		}
1607
		cfg.Genesis = core.DefaultRopstenGenesisBlock()
1608
		SetDNSDiscoveryDefaults(cfg, params.RopstenGenesisHash)
1609 1610 1611 1612 1613
	case ctx.GlobalBool(RinkebyFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 4
		}
		cfg.Genesis = core.DefaultRinkebyGenesisBlock()
1614
		SetDNSDiscoveryDefaults(cfg, params.RinkebyGenesisHash)
1615 1616 1617 1618 1619
	case ctx.GlobalBool(GoerliFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 5
		}
		cfg.Genesis = core.DefaultGoerliGenesisBlock()
1620
		SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash)
1621
	case ctx.GlobalBool(CalaverasFlag.Name):
1622
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
1623
			cfg.NetworkId = 123 // https://gist.github.com/holiman/c5697b041b3dc18c50a5cdd382cbdd16
1624
		}
1625
		cfg.Genesis = core.DefaultCalaverasGenesisBlock()
1626
	case ctx.GlobalBool(DeveloperFlag.Name):
1627 1628 1629
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 1337
		}
1630
		cfg.SyncMode = downloader.FullSync
1631 1632
		// Create new developer account or reuse existing one
		var (
1633 1634 1635
			developer  accounts.Account
			passphrase string
			err        error
1636
		)
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646
		if list := MakePasswordList(ctx); len(list) > 0 {
			// Just take the first value. Although the function returns a possible multiple values and
			// some usages iterate through them as attempts, that doesn't make sense in this setting,
			// when we're definitely concerned with only one account.
			passphrase = list[0]
		}
		// setEtherbase has been called above, configuring the miner address from command line flags.
		if cfg.Miner.Etherbase != (common.Address{}) {
			developer = accounts.Account{Address: cfg.Miner.Etherbase}
		} else if accs := ks.Accounts(); len(accs) > 0 {
1647 1648
			developer = ks.Accounts()[0]
		} else {
1649
			developer, err = ks.NewAccount(passphrase)
1650 1651 1652 1653
			if err != nil {
				Fatalf("Failed to create developer account: %v", err)
			}
		}
1654
		if err := ks.Unlock(developer, passphrase); err != nil {
1655 1656 1657 1658
			Fatalf("Failed to unlock developer account: %v", err)
		}
		log.Info("Using developer account", "address", developer.Address)

1659
		// Create a new developer genesis block or reuse existing one
1660
		cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address)
1661 1662 1663
		if ctx.GlobalIsSet(DataDirFlag.Name) {
			// Check if we have an already initialized chain and fall back to
			// that if so. Otherwise we need to generate a new genesis spec.
1664
			chaindb := MakeChainDatabase(ctx, stack, false) // TODO (MariusVanDerWijden) make this read only
1665 1666 1667 1668 1669
			if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) {
				cfg.Genesis = nil // fallback to db content
			}
			chaindb.Close()
		}
1670
		if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) {
1671
			cfg.Miner.GasPrice = big.NewInt(1)
1672
		}
1673 1674
	default:
		if cfg.NetworkId == 1 {
1675
			SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
1676 1677 1678 1679
		}
	}
}

1680
// SetDNSDiscoveryDefaults configures DNS discovery with the given URL if
1681
// no URLs are set.
1682
func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) {
1683
	if cfg.EthDiscoveryURLs != nil {
1684 1685
		return // already set through flags/config
	}
1686
	protocol := "all"
1687 1688 1689 1690
	if cfg.SyncMode == downloader.LightSync {
		protocol = "les"
	}
	if url := params.KnownDNSNetwork(genesis, protocol); url != "" {
1691
		cfg.EthDiscoveryURLs = []string{url}
1692
		cfg.SnapDiscoveryURLs = cfg.EthDiscoveryURLs
1693
	}
1694
}
1695

1696
// RegisterEthService adds an Ethereum client to the stack.
1697 1698 1699
// The second return value is the full node instance, which may be nil if the
// node is running as a light client.
func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend, *eth.Ethereum) {
1700
	if cfg.SyncMode == downloader.LightSync {
R
rene 已提交
1701 1702 1703 1704
		backend, err := les.New(stack, cfg)
		if err != nil {
			Fatalf("Failed to register the Ethereum service: %v", err)
		}
1705
		stack.RegisterAPIs(tracers.APIs(backend.ApiBackend))
1706
		return backend.ApiBackend, nil
1707 1708 1709 1710 1711 1712 1713
	}
	backend, err := eth.New(stack, cfg)
	if err != nil {
		Fatalf("Failed to register the Ethereum service: %v", err)
	}
	if cfg.LightServ > 0 {
		_, err := les.NewLesServer(stack, backend, cfg)
R
rene 已提交
1714
		if err != nil {
1715
			Fatalf("Failed to create the LES server: %v", err)
R
rene 已提交
1716
		}
1717
	}
1718
	stack.RegisterAPIs(tracers.APIs(backend.APIBackend))
1719
	return backend.APIBackend, backend
1720 1721
}

1722
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
S
Sarlor 已提交
1723
// the given node.
R
rene 已提交
1724 1725
func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url string) {
	if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil {
1726
		Fatalf("Failed to register the Ethereum Stats service: %v", err)
1727 1728 1729
	}
}

1730
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
R
rene 已提交
1731 1732
func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, cfg node.Config) {
	if err := graphql.New(stack, backend, cfg.GraphQLCors, cfg.GraphQLVirtualHosts); err != nil {
1733 1734 1735 1736
		Fatalf("Failed to register the GraphQL service: %v", err)
	}
}

1737 1738 1739
func SetupMetrics(ctx *cli.Context) {
	if metrics.Enabled {
		log.Info("Enabling metrics collection")
1740

1741 1742 1743 1744 1745 1746 1747 1748 1749
		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 {
1750 1751
			tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name))

1752
			log.Info("Enabling metrics export to InfluxDB")
1753 1754 1755

			go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap)
		}
1756 1757 1758 1759 1760 1761

		if ctx.GlobalIsSet(MetricsHTTPFlag.Name) {
			address := fmt.Sprintf("%s:%d", ctx.GlobalString(MetricsHTTPFlag.Name), ctx.GlobalInt(MetricsPortFlag.Name))
			log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address)
			exp.Setup(address)
		}
1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775
	}
}

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]
			}
1776 1777
		}
	}
1778 1779

	return tagsMap
1780 1781
}

1782
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
1783
func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.Database {
1784
	var (
1785
		cache   = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
1786
		handles = MakeDatabaseHandles()
1787 1788 1789

		err     error
		chainDb ethdb.Database
1790
	)
1791
	if ctx.GlobalString(SyncModeFlag.Name) == "light" {
1792
		name := "lightchaindata"
1793
		chainDb, err = stack.OpenDatabase(name, cache, handles, "", readonly)
1794 1795
	} else {
		name := "chaindata"
1796
		chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly)
1797
	}
1798
	if err != nil {
1799
		Fatalf("Could not open database: %v", err)
1800
	}
1801 1802 1803
	return chainDb
}

F
Felix Lange 已提交
1804 1805 1806
func MakeGenesis(ctx *cli.Context) *core.Genesis {
	var genesis *core.Genesis
	switch {
1807 1808
	case ctx.GlobalBool(MainnetFlag.Name):
		genesis = core.DefaultGenesisBlock()
1809
	case ctx.GlobalBool(RopstenFlag.Name):
1810
		genesis = core.DefaultRopstenGenesisBlock()
1811 1812
	case ctx.GlobalBool(RinkebyFlag.Name):
		genesis = core.DefaultRinkebyGenesisBlock()
1813 1814
	case ctx.GlobalBool(GoerliFlag.Name):
		genesis = core.DefaultGoerliGenesisBlock()
1815 1816
	case ctx.GlobalBool(CalaverasFlag.Name):
		genesis = core.DefaultCalaverasGenesisBlock()
1817 1818
	case ctx.GlobalBool(DeveloperFlag.Name):
		Fatalf("Developer chains are ephemeral")
F
Felix Lange 已提交
1819 1820 1821 1822
	}
	return genesis
}

1823
// MakeChain creates a chain manager from set command line flags.
1824
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
1825
	var err error
1826
	chainDb = MakeChainDatabase(ctx, stack, false) // TODO(rjl493456442) support read-only database
F
Felix Lange 已提交
1827 1828 1829 1830
	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
	if err != nil {
		Fatalf("%v", err)
	}
1831 1832 1833 1834 1835 1836
	var engine consensus.Engine
	if config.Clique != nil {
		engine = clique.New(config.Clique, chainDb)
	} else {
		engine = ethash.NewFaker()
		if !ctx.GlobalBool(FakePoWFlag.Name) {
1837
			engine = ethash.New(ethash.Config{
1838 1839 1840 1841 1842 1843 1844 1845
				CacheDir:         stack.ResolvePath(ethconfig.Defaults.Ethash.CacheDir),
				CachesInMem:      ethconfig.Defaults.Ethash.CachesInMem,
				CachesOnDisk:     ethconfig.Defaults.Ethash.CachesOnDisk,
				CachesLockMmap:   ethconfig.Defaults.Ethash.CachesLockMmap,
				DatasetDir:       stack.ResolvePath(ethconfig.Defaults.Ethash.DatasetDir),
				DatasetsInMem:    ethconfig.Defaults.Ethash.DatasetsInMem,
				DatasetsOnDisk:   ethconfig.Defaults.Ethash.DatasetsOnDisk,
				DatasetsLockMmap: ethconfig.Defaults.Ethash.DatasetsLockMmap,
1846
			}, nil, false)
1847 1848
		}
	}
1849 1850 1851 1852
	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
	}
	cache := &core.CacheConfig{
1853
		TrieCleanLimit:      ethconfig.Defaults.TrieCleanCache,
1854
		TrieCleanNoPrefetch: ctx.GlobalBool(CacheNoPrefetchFlag.Name),
1855
		TrieDirtyLimit:      ethconfig.Defaults.TrieDirtyCache,
1856
		TrieDirtyDisabled:   ctx.GlobalString(GCModeFlag.Name) == "archive",
1857 1858
		TrieTimeLimit:       ethconfig.Defaults.TrieTimeout,
		SnapshotLimit:       ethconfig.Defaults.SnapshotCache,
1859 1860 1861 1862 1863
		Preimages:           ctx.GlobalBool(CachePreimagesFlag.Name),
	}
	if cache.TrieDirtyDisabled && !cache.Preimages {
		cache.Preimages = true
		log.Info("Enabling recording of key preimages since archive mode is used")
1864
	}
1865
	if !ctx.GlobalBool(SnapshotFlag.Name) {
1866 1867
		cache.SnapshotLimit = 0 // Disabled
	}
1868 1869
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
		cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
1870 1871
	}
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
1872
		cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
1873
	}
F
Felix Lange 已提交
1874
	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
1875 1876 1877 1878

	// TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only.
	// Disable transaction indexing/unindexing by default.
	chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil)
O
obscuren 已提交
1879
	if err != nil {
F
Felix Lange 已提交
1880
		Fatalf("Can't create BlockChain: %v", err)
O
obscuren 已提交
1881
	}
1882
	return chain, chainDb
1883
}
1884 1885 1886 1887 1888 1889 1890 1891 1892

// 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
1893
	var preloads []string
1894 1895

	for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") {
1896
		preloads = append(preloads, strings.TrimSpace(file))
1897 1898 1899
	}
	return preloads
}
1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923

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