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

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

69 70 71 72 73
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:
74
	{{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
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

	OriginCommandHelpTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} [arguments...]
{{if .Description}}{{.Description}}
{{end}}{{if .Subcommands}}
SUBCOMMANDS:
	{{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
	{{end}}{{end}}{{if .Flags}}
OPTIONS:
{{range $.Flags}}{{"\t"}}{{.}}
{{end}}
{{end}}`
91 92
)

93 94 95 96 97 98 99 100 101 102 103 104 105
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}}
`
106
	cli.CommandHelpTemplate = CommandHelpTemplate
107
	cli.HelpPrinter = printHelp
108 109
}

F
Felix Lange 已提交
110
// NewApp creates an app with sane defaults.
111
func NewApp(gitCommit, gitDate, usage string) *cli.App {
F
Felix Lange 已提交
112
	app := cli.NewApp()
113
	app.Name = filepath.Base(os.Args[0])
F
Felix Lange 已提交
114 115
	app.Author = ""
	app.Email = ""
116
	app.Version = params.VersionWithCommit(gitCommit, gitDate)
F
Felix Lange 已提交
117 118 119 120
	app.Usage = usage
	return app
}

121 122 123 124 125 126 127 128 129 130 131
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()
}

132 133 134 135 136 137 138 139 140
// 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
141
	DataDirFlag = DirectoryFlag{
142
		Name:  "datadir",
143
		Usage: "Data directory for the databases and keystore",
144
		Value: DirectoryString(node.DefaultDataDir()),
145
	}
146 147 148 149
	AncientFlag = DirectoryFlag{
		Name:  "datadir.ancient",
		Usage: "Data directory for ancient chain segments (default = inside chaindata)",
	}
K
Kobi Gurkan 已提交
150 151 152 153
	KeyStoreDirFlag = DirectoryFlag{
		Name:  "keystore",
		Usage: "Directory for the keystore (default = inside the datadir)",
	}
154 155
	NoUSBFlag = cli.BoolFlag{
		Name:  "nousb",
O
Oli Bye 已提交
156
		Usage: "Disables monitoring for and managing USB hardware wallets",
157
	}
158 159 160 161 162
	SmartCardDaemonPathFlag = cli.StringFlag{
		Name:  "pcscdpath",
		Usage: "Path to the smartcard daemon (pcscd) socket file",
		Value: pcsclite.PCSCDSockName,
	}
163
	NetworkIdFlag = cli.Uint64Flag{
Z
zelig 已提交
164
		Name:  "networkid",
165
		Usage: "Network identifier (integer, 1=Frontier, 3=Ropsten, 4=Rinkeby, 5=Görli)",
166
		Value: eth.DefaultConfig.NetworkId,
Z
zelig 已提交
167
	}
168 169 170
	GoerliFlag = cli.BoolFlag{
		Name:  "goerli",
		Usage: "Görli network: pre-configured proof-of-authority test network",
171
	}
172 173 174 175
	YoloV1Flag = cli.BoolFlag{
		Name:  "yolov1",
		Usage: "YOLOv1 network: pre-configured proof-of-authority shortlived test network.",
	}
176 177 178 179
	RinkebyFlag = cli.BoolFlag{
		Name:  "rinkeby",
		Usage: "Rinkeby network: pre-configured proof-of-authority test network",
	}
180 181 182
	RopstenFlag = cli.BoolFlag{
		Name:  "ropsten",
		Usage: "Ropsten network: pre-configured proof-of-work test network",
183
	}
184
	DeveloperFlag = cli.BoolFlag{
185
		Name:  "dev",
186 187 188 189 190
		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)",
191
	}
192 193
	IdentityFlag = cli.StringFlag{
		Name:  "identity",
194
		Usage: "Custom node name",
195
	}
Z
zelig 已提交
196 197 198
	DocRootFlag = DirectoryFlag{
		Name:  "docroot",
		Usage: "Document Root for HTTPClient file scheme",
199
		Value: DirectoryString(homeDir()),
Z
zelig 已提交
200
	}
201 202
	ExitWhenSyncedFlag = cli.BoolFlag{
		Name:  "exitwhensynced",
203
		Usage: "Exits after block synchronisation completes",
204
	}
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
	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)",
	}
221 222 223 224 225 226
	defaultSyncMode = eth.DefaultConfig.SyncMode
	SyncModeFlag    = TextMarshalerFlag{
		Name:  "syncmode",
		Usage: `Blockchain sync mode ("fast", "full", or "light")`,
		Value: &defaultSyncMode,
	}
227 228 229 230 231
	GCModeFlag = cli.StringFlag{
		Name:  "gcmode",
		Usage: `Blockchain garbage collection mode ("full", "archive")`,
		Value: "full",
	}
232 233 234 235
	SnapshotFlag = cli.BoolFlag{
		Name:  "snapshot",
		Usage: `Enables snapshot-database mode -- experimental work in progress feature`,
	}
236 237 238 239 240
	TxLookupLimitFlag = cli.Int64Flag{
		Name:  "txlookuplimit",
		Usage: "Number of recent blocks to maintain transactions index by-hash for (default = index all blocks)",
		Value: 0,
	}
241 242 243 244 245 246 247 248
	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>)",
	}
249 250 251
	// Light server and client settings
	LightServeFlag = cli.IntFlag{
		Name:  "light.serve",
252
		Usage: "Maximum percentage of time allowed for serving LES requests (multi-threaded processing allows values over 100)",
253
		Value: eth.DefaultConfig.LightServ,
254
	}
255 256 257 258
	LightIngressFlag = cli.IntFlag{
		Name:  "light.ingress",
		Usage: "Incoming bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)",
		Value: eth.DefaultConfig.LightIngress,
259
	}
260 261 262 263
	LightEgressFlag = cli.IntFlag{
		Name:  "light.egress",
		Usage: "Outgoing bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)",
		Value: eth.DefaultConfig.LightEgress,
264
	}
265 266 267
	LightMaxPeersFlag = cli.IntFlag{
		Name:  "light.maxpeers",
		Usage: "Maximum number of light clients to serve, or light servers to attach to",
268
		Value: eth.DefaultConfig.LightPeers,
269
	}
270 271 272 273
	UltraLightServersFlag = cli.StringFlag{
		Name:  "ulc.servers",
		Usage: "List of trusted ultra-light servers",
		Value: strings.Join(eth.DefaultConfig.UltraLightServers, ","),
274
	}
275 276 277 278 279 280 281 282
	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",
283
	}
284 285 286 287 288 289 290 291
	// 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)",
292
		Value: eth.DefaultConfig.Ethash.CachesInMem,
293 294 295 296
	}
	EthashCachesOnDiskFlag = cli.IntFlag{
		Name:  "ethash.cachesondisk",
		Usage: "Number of recent ethash caches to keep on disk (16MB each)",
297
		Value: eth.DefaultConfig.Ethash.CachesOnDisk,
298
	}
299 300 301 302
	EthashCachesLockMmapFlag = cli.BoolFlag{
		Name:  "ethash.cacheslockmmap",
		Usage: "Lock memory maps of recent ethash caches",
	}
303 304
	EthashDatasetDirFlag = DirectoryFlag{
		Name:  "ethash.dagdir",
305 306
		Usage: "Directory to store the ethash mining DAGs",
		Value: DirectoryString(eth.DefaultConfig.Ethash.DatasetDir),
307 308 309 310
	}
	EthashDatasetsInMemoryFlag = cli.IntFlag{
		Name:  "ethash.dagsinmem",
		Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
311
		Value: eth.DefaultConfig.Ethash.DatasetsInMem,
312 313 314 315
	}
	EthashDatasetsOnDiskFlag = cli.IntFlag{
		Name:  "ethash.dagsondisk",
		Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
316
		Value: eth.DefaultConfig.Ethash.DatasetsOnDisk,
317
	}
318 319 320 321
	EthashDatasetsLockMmapFlag = cli.BoolFlag{
		Name:  "ethash.dagslockmmap",
		Usage: "Lock memory maps for recent ethash mining DAGs",
	}
322
	// Transaction pool settings
323 324 325 326
	TxPoolLocalsFlag = cli.StringFlag{
		Name:  "txpool.locals",
		Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)",
	}
327 328 329 330
	TxPoolNoLocalsFlag = cli.BoolFlag{
		Name:  "txpool.nolocals",
		Usage: "Disables price exemptions for locally submitted transactions",
	}
331 332 333 334 335 336 337 338 339 340
	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,
	}
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
	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,
	}
376 377 378
	// Performance tuning settings
	CacheFlag = cli.IntFlag{
		Name:  "cache",
379
		Usage: "Megabytes of memory allocated to internal caching (default = 4096 mainnet full node, 128 light mode)",
380 381 382 383 384
		Value: 1024,
	}
	CacheDatabaseFlag = cli.IntFlag{
		Name:  "cache.database",
		Usage: "Percentage of cache memory allowance to use for database io",
385 386 387 388
		Value: 50,
	}
	CacheTrieFlag = cli.IntFlag{
		Name:  "cache.trie",
389 390
		Usage: "Percentage of cache memory allowance to use for trie caching (default = 15% full mode, 30% archive mode)",
		Value: 15,
391 392 393
	}
	CacheGCFlag = cli.IntFlag{
		Name:  "cache.gc",
394
		Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)",
395
		Value: 25,
396
	}
397 398 399 400 401
	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,
	}
402 403 404 405
	CacheNoPrefetchFlag = cli.BoolFlag{
		Name:  "cache.noprefetch",
		Usage: "Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data)",
	}
406 407 408 409
	// Miner settings
	MiningEnabledFlag = cli.BoolFlag{
		Name:  "mine",
		Usage: "Enable mining",
410
	}
411
	MinerThreadsFlag = cli.IntFlag{
412
		Name:  "miner.threads",
413
		Usage: "Number of CPU threads to use for mining",
414 415 416 417 418
		Value: 0,
	}
	MinerNotifyFlag = cli.StringFlag{
		Name:  "miner.notify",
		Usage: "Comma separated HTTP URL list to notify of new work packages",
419
	}
420 421 422
	MinerGasTargetFlag = cli.Uint64Flag{
		Name:  "miner.gastarget",
		Usage: "Target gas floor for mined blocks",
423
		Value: eth.DefaultConfig.Miner.GasFloor,
424
	}
425 426 427
	MinerGasLimitFlag = cli.Uint64Flag{
		Name:  "miner.gaslimit",
		Usage: "Target gas ceiling for mined blocks",
428
		Value: eth.DefaultConfig.Miner.GasCeil,
429
	}
430 431
	MinerGasPriceFlag = BigFlag{
		Name:  "miner.gasprice",
432
		Usage: "Minimum gas price for mining a transaction",
433
		Value: eth.DefaultConfig.Miner.GasPrice,
Z
zelig 已提交
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",
	}
	MinerExtraDataFlag = cli.StringFlag{
		Name:  "miner.extradata",
442
		Usage: "Block extra data set by the miner (default = client version)",
Z
zelig 已提交
443
	}
444 445
	MinerRecommitIntervalFlag = cli.DurationFlag{
		Name:  "miner.recommit",
446
		Usage: "Time interval to recreate the block being mined",
447
		Value: eth.DefaultConfig.Miner.Recommit,
448
	}
449 450 451 452
	MinerNoVerfiyFlag = cli.BoolFlag{
		Name:  "miner.noverify",
		Usage: "Disable remote sealing verification",
	}
453
	// Account settings
Z
zelig 已提交
454 455
	UnlockedAccountFlag = cli.StringFlag{
		Name:  "unlock",
456
		Usage: "Comma separated list of accounts to unlock",
Z
zelig 已提交
457 458 459 460
		Value: "",
	}
	PasswordFileFlag = cli.StringFlag{
		Name:  "password",
A
ayeowch 已提交
461
		Usage: "Password file to use for non-interactive password input",
Z
zelig 已提交
462
		Value: "",
Z
zelig 已提交
463
	}
464 465 466 467 468
	ExternalSignerFlag = cli.StringFlag{
		Name:  "signer",
		Usage: "External signer (url or path to ipc file)",
		Value: "",
	}
469 470 471 472
	VMEnableDebugFlag = cli.BoolFlag{
		Name:  "vmdebug",
		Usage: "Record information useful for VM and contract debugging",
	}
473 474 475 476
	InsecureUnlockAllowedFlag = cli.BoolFlag{
		Name:  "allow-insecure-unlock",
		Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http",
	}
477 478 479 480
	RPCGlobalGasCap = cli.Uint64Flag{
		Name:  "rpc.gascap",
		Usage: "Sets a cap on gas that can be used in eth_call/estimateGas",
	}
481 482 483 484 485
	RPCGlobalTxFeeCap = cli.Float64Flag{
		Name:  "rpc.txfeecap",
		Usage: "Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)",
		Value: eth.DefaultConfig.RPCTxFeeCap,
	}
486 487 488 489 490
	// Logging and debug settings
	EthStatsURLFlag = cli.StringFlag{
		Name:  "ethstats",
		Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)",
	}
491 492 493 494
	FakePoWFlag = cli.BoolFlag{
		Name:  "fakepow",
		Usage: "Disables proof-of-work verification",
	}
495 496 497 498
	NoCompactionFlag = cli.BoolFlag{
		Name:  "nocompaction",
		Usage: "Disables db compaction after import",
	}
499
	// RPC settings
500 501 502 503 504 505 506 507
	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)",
	}
508 509
	HTTPEnabledFlag = cli.BoolFlag{
		Name:  "http",
510
		Usage: "Enable the HTTP-RPC server",
511
	}
512 513
	HTTPListenAddrFlag = cli.StringFlag{
		Name:  "http.addr",
514
		Usage: "HTTP-RPC server listening interface",
515
		Value: node.DefaultHTTPHost,
516
	}
517 518
	HTTPPortFlag = cli.IntFlag{
		Name:  "http.port",
519
		Usage: "HTTP-RPC server listening port",
520
		Value: node.DefaultHTTPPort,
521
	}
522 523
	HTTPCORSDomainFlag = cli.StringFlag{
		Name:  "http.corsdomain",
524
		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
525 526
		Value: "",
	}
527 528
	HTTPVirtualHostsFlag = cli.StringFlag{
		Name:  "http.vhosts",
529
		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
530
		Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
531
	}
532 533
	HTTPApiFlag = cli.StringFlag{
		Name:  "http.api",
534
		Usage: "API's offered over the HTTP-RPC interface",
535
		Value: "",
536
	}
537
	WSEnabledFlag = cli.BoolFlag{
538
		Name:  "ws",
539 540 541
		Usage: "Enable the WS-RPC server",
	}
	WSListenAddrFlag = cli.StringFlag{
542
		Name:  "ws.addr",
543
		Usage: "WS-RPC server listening interface",
544
		Value: node.DefaultWSHost,
545 546
	}
	WSPortFlag = cli.IntFlag{
547
		Name:  "ws.port",
548
		Usage: "WS-RPC server listening port",
549
		Value: node.DefaultWSPort,
550 551
	}
	WSApiFlag = cli.StringFlag{
552
		Name:  "ws.api",
553
		Usage: "API's offered over the WS-RPC interface",
554
		Value: "",
555
	}
B
Bas van Kervel 已提交
556
	WSAllowedOriginsFlag = cli.StringFlag{
557
		Name:  "ws.origins",
B
Bas van Kervel 已提交
558
		Usage: "Origins from which to accept websockets requests",
559
		Value: "",
560
	}
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
	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, ","),
	}
585 586
	ExecFlag = cli.StringFlag{
		Name:  "exec",
587
		Usage: "Execute JavaScript statement",
588
	}
589
	PreloadJSFlag = cli.StringFlag{
590 591 592
		Name:  "preload",
		Usage: "Comma separated list of JavaScript files to preload into the console",
	}
593

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

645
	// ATM the url is left to the user and deployment to
Z
CLI:  
zelig 已提交
646 647
	JSpathFlag = cli.StringFlag{
		Name:  "jspath",
648
		Usage: "JavaScript root path for `loadScript`",
Z
CLI:  
zelig 已提交
649 650
		Value: ".",
	}
651 652

	// Gas price oracle settings
653
	GpoBlocksFlag = cli.IntFlag{
654
		Name:  "gpo.blocks",
655
		Usage: "Number of recent blocks to check for gas prices",
656
		Value: eth.DefaultConfig.GPO.Blocks,
Z
zsfelfoldi 已提交
657
	}
658
	GpoPercentileFlag = cli.IntFlag{
659
		Name:  "gpo.percentile",
660
		Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices",
661
		Value: eth.DefaultConfig.GPO.Percentile,
Z
zsfelfoldi 已提交
662
	}
663 664 665 666 667 668 669 670 671 672 673 674 675 676
	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,
	}
677 678 679 680
	WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{
		Name:  "shh.restrict-light",
		Usage: "Restrict connection between two whisper light clients",
	}
681 682 683

	// Metrics flags
	MetricsEnabledFlag = cli.BoolFlag{
684
		Name:  "metrics",
685 686
		Usage: "Enable metrics collection and reporting",
	}
687 688 689 690
	MetricsEnabledExpensiveFlag = cli.BoolFlag{
		Name:  "metrics.expensive",
		Usage: "Enable expensive metrics collection and reporting",
	}
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
	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",
	}
715 716 717
	// 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.
718
	// https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key
719 720 721 722
	MetricsInfluxDBTagsFlag = cli.StringFlag{
		Name:  "metrics.influxdb.tags",
		Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements",
		Value: "host=localhost",
723
	}
724 725 726 727 728 729 730 731 732 733
	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: "",
	}
734 735
)

736
// MakeDataDir retrieves the currently requested data directory, terminating
737
// if none (or the empty string) is specified. If the node is starting a testnet,
738
// then a subdirectory of the specified datadir will be used.
739
func MakeDataDir(ctx *cli.Context) string {
740
	if path := ctx.GlobalString(DataDirFlag.Name); path != "" {
741 742 743 744 745 746 747 748
		if ctx.GlobalBool(LegacyTestnetFlag.Name) || ctx.GlobalBool(RopstenFlag.Name) {
			// Maintain compatibility with older Geth configurations storing the
			// Ropsten database in `testnet` instead of `ropsten`.
			legacyPath := filepath.Join(path, "testnet")
			if _, err := os.Stat(legacyPath); !os.IsNotExist(err) {
				return legacyPath
			}
			return filepath.Join(path, "ropsten")
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 757 758
		if ctx.GlobalBool(YoloV1Flag.Name) {
			return filepath.Join(path, "yolo-v1")
		}
759
		return path
760
	}
761
	Fatalf("Cannot determine default data directory, please set manually (--datadir)")
762
	return ""
763 764
}

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

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

798
// setBootstrapNodes creates a list of bootstrap nodes from the command line
799
// flags, reverting to pre-configured ones if none have been specified.
800
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
801
	urls := params.MainnetBootnodes
802
	switch {
803 804 805
	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(LegacyBootnodesV4Flag.Name):
		if ctx.GlobalIsSet(LegacyBootnodesV4Flag.Name) {
			urls = splitAndTrim(ctx.GlobalString(LegacyBootnodesV4Flag.Name))
806
		} else {
807
			urls = splitAndTrim(ctx.GlobalString(BootnodesFlag.Name))
808
		}
809 810
	case ctx.GlobalBool(LegacyTestnetFlag.Name) || ctx.GlobalBool(RopstenFlag.Name):
		urls = params.RopstenBootnodes
811 812
	case ctx.GlobalBool(RinkebyFlag.Name):
		urls = params.RinkebyBootnodes
813 814
	case ctx.GlobalBool(GoerliFlag.Name):
		urls = params.GoerliBootnodes
815 816
	case ctx.GlobalBool(YoloV1Flag.Name):
		urls = params.YoloV1Bootnodes
817 818
	case cfg.BootstrapNodes != nil:
		return // already set, don't apply defaults.
819 820
	}

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

834
// setBootstrapNodesV5 creates a list of bootstrap nodes from the command line
835
// flags, reverting to pre-configured ones if none have been specified.
836
func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
837
	urls := params.MainnetBootnodes
838
	switch {
839 840 841
	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(LegacyBootnodesV5Flag.Name):
		if ctx.GlobalIsSet(LegacyBootnodesV5Flag.Name) {
			urls = splitAndTrim(ctx.GlobalString(LegacyBootnodesV5Flag.Name))
842
		} else {
843
			urls = splitAndTrim(ctx.GlobalString(BootnodesFlag.Name))
844
		}
845 846
	case ctx.GlobalBool(RopstenFlag.Name):
		urls = params.RopstenBootnodes
847
	case ctx.GlobalBool(RinkebyFlag.Name):
848
		urls = params.RinkebyBootnodes
849 850
	case ctx.GlobalBool(GoerliFlag.Name):
		urls = params.GoerliBootnodes
851 852
	case ctx.GlobalBool(YoloV1Flag.Name):
		urls = params.YoloV1Bootnodes
853
	case cfg.BootstrapNodesV5 != nil:
854
		return // already set, don't apply defaults.
855 856
	}

857
	cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls))
858
	for _, url := range urls {
859 860 861 862 863 864 865
		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)
866 867 868 869
		}
	}
}

870
// setListenAddress creates a TCP listening address string from set command
871
// line flags.
872 873 874 875
func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
	if ctx.GlobalIsSet(ListenPortFlag.Name) {
		cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
	}
876 877
}

878 879 880 881 882 883 884 885
// 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
886 887 888
	}
}

889 890 891
// splitAndTrim splits input separated by a comma
// and trims excessive white space from the substrings.
func splitAndTrim(input string) []string {
892 893 894 895 896 897 898
	result := strings.Split(input, ",")
	for i, r := range result {
		result[i] = strings.TrimSpace(r)
	}
	return result
}

899
// setHTTP creates the HTTP RPC listener interface string from the set
900
// command line flags, returning empty if the HTTP endpoint is disabled.
901
func setHTTP(ctx *cli.Context, cfg *node.Config) {
902 903
	if ctx.GlobalBool(LegacyRPCEnabledFlag.Name) && cfg.HTTPHost == "" {
		log.Warn("The flag --rpc is deprecated and will be removed in the future, please use --http")
904
		cfg.HTTPHost = "127.0.0.1"
905 906 907
		if ctx.GlobalIsSet(LegacyRPCListenAddrFlag.Name) {
			cfg.HTTPHost = ctx.GlobalString(LegacyRPCListenAddrFlag.Name)
			log.Warn("The flag --rpcaddr is deprecated and will be removed in the future, please use --http.addr")
908 909
		}
	}
910 911 912 913 914
	if ctx.GlobalBool(HTTPEnabledFlag.Name) && cfg.HTTPHost == "" {
		cfg.HTTPHost = "127.0.0.1"
		if ctx.GlobalIsSet(HTTPListenAddrFlag.Name) {
			cfg.HTTPHost = ctx.GlobalString(HTTPListenAddrFlag.Name)
		}
915
	}
916 917 918 919

	if ctx.GlobalIsSet(LegacyRPCPortFlag.Name) {
		cfg.HTTPPort = ctx.GlobalInt(LegacyRPCPortFlag.Name)
		log.Warn("The flag --rpcport is deprecated and will be removed in the future, please use --http.port")
920
	}
921 922
	if ctx.GlobalIsSet(HTTPPortFlag.Name) {
		cfg.HTTPPort = ctx.GlobalInt(HTTPPortFlag.Name)
923
	}
924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946

	if ctx.GlobalIsSet(LegacyRPCCORSDomainFlag.Name) {
		cfg.HTTPCors = splitAndTrim(ctx.GlobalString(LegacyRPCCORSDomainFlag.Name))
		log.Warn("The flag --rpccorsdomain is deprecated and will be removed in the future, please use --http.corsdomain")
	}
	if ctx.GlobalIsSet(HTTPCORSDomainFlag.Name) {
		cfg.HTTPCors = splitAndTrim(ctx.GlobalString(HTTPCORSDomainFlag.Name))
	}

	if ctx.GlobalIsSet(LegacyRPCApiFlag.Name) {
		cfg.HTTPModules = splitAndTrim(ctx.GlobalString(LegacyRPCApiFlag.Name))
		log.Warn("The flag --rpcapi is deprecated and will be removed in the future, please use --http.api")
	}
	if ctx.GlobalIsSet(HTTPApiFlag.Name) {
		cfg.HTTPModules = splitAndTrim(ctx.GlobalString(HTTPApiFlag.Name))
	}

	if ctx.GlobalIsSet(LegacyRPCVirtualHostsFlag.Name) {
		cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(LegacyRPCVirtualHostsFlag.Name))
		log.Warn("The flag --rpcvhosts is deprecated and will be removed in the future, please use --http.vhosts")
	}
	if ctx.GlobalIsSet(HTTPVirtualHostsFlag.Name) {
		cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(HTTPVirtualHostsFlag.Name))
947
	}
948 949
}

950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
// 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))
	}
}

968
// setWS creates the WebSocket RPC listener interface string from the set
969
// command line flags, returning empty if the HTTP endpoint is disabled.
970 971 972
func setWS(ctx *cli.Context, cfg *node.Config) {
	if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" {
		cfg.WSHost = "127.0.0.1"
973 974 975 976
		if ctx.GlobalIsSet(LegacyWSListenAddrFlag.Name) {
			cfg.WSHost = ctx.GlobalString(LegacyWSListenAddrFlag.Name)
			log.Warn("The flag --wsaddr is deprecated and will be removed in the future, please use --ws.addr")
		}
977 978 979 980
		if ctx.GlobalIsSet(WSListenAddrFlag.Name) {
			cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name)
		}
	}
981 982 983 984
	if ctx.GlobalIsSet(LegacyWSPortFlag.Name) {
		cfg.WSPort = ctx.GlobalInt(LegacyWSPortFlag.Name)
		log.Warn("The flag --wsport is deprecated and will be removed in the future, please use --ws.port")
	}
985 986 987
	if ctx.GlobalIsSet(WSPortFlag.Name) {
		cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name)
	}
988 989 990 991 992

	if ctx.GlobalIsSet(LegacyWSAllowedOriginsFlag.Name) {
		cfg.WSOrigins = splitAndTrim(ctx.GlobalString(LegacyWSAllowedOriginsFlag.Name))
		log.Warn("The flag --wsorigins is deprecated and will be removed in the future, please use --ws.origins")
	}
993
	if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) {
994
		cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name))
995
	}
996 997 998 999 1000

	if ctx.GlobalIsSet(LegacyWSApiFlag.Name) {
		cfg.WSModules = splitAndTrim(ctx.GlobalString(LegacyWSApiFlag.Name))
		log.Warn("The flag --wsapi is deprecated and will be removed in the future, please use --ws.api")
	}
1001
	if ctx.GlobalIsSet(WSApiFlag.Name) {
1002
		cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name))
1003 1004 1005 1006 1007 1008
	}
}

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

1018 1019
// setLes configures the les server and ultra light client settings from the command line flags.
func setLes(ctx *cli.Context, cfg *eth.Config) {
1020 1021 1022
	if ctx.GlobalIsSet(LegacyLightServFlag.Name) {
		cfg.LightServ = ctx.GlobalInt(LegacyLightServFlag.Name)
		log.Warn("The flag --lightserv is deprecated and will be removed in the future, please use --light.serve")
1023 1024 1025 1026 1027 1028
	}
	if ctx.GlobalIsSet(LightServeFlag.Name) {
		cfg.LightServ = ctx.GlobalInt(LightServeFlag.Name)
	}
	if ctx.GlobalIsSet(LightIngressFlag.Name) {
		cfg.LightIngress = ctx.GlobalInt(LightIngressFlag.Name)
1029
	}
1030 1031
	if ctx.GlobalIsSet(LightEgressFlag.Name) {
		cfg.LightEgress = ctx.GlobalInt(LightEgressFlag.Name)
1032
	}
1033 1034 1035
	if ctx.GlobalIsSet(LegacyLightPeersFlag.Name) {
		cfg.LightPeers = ctx.GlobalInt(LegacyLightPeersFlag.Name)
		log.Warn("The flag --lightpeers is deprecated and will be removed in the future, please use --light.maxpeers")
1036
	}
1037 1038
	if ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
		cfg.LightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name)
1039
	}
1040 1041
	if ctx.GlobalIsSet(UltraLightServersFlag.Name) {
		cfg.UltraLightServers = strings.Split(ctx.GlobalString(UltraLightServersFlag.Name), ",")
1042
	}
1043 1044
	if ctx.GlobalIsSet(UltraLightFractionFlag.Name) {
		cfg.UltraLightFraction = ctx.GlobalInt(UltraLightFractionFlag.Name)
1045
	}
1046 1047 1048
	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
1049
	}
1050 1051
	if ctx.GlobalIsSet(UltraLightOnlyAnnounceFlag.Name) {
		cfg.UltraLightOnlyAnnounce = ctx.GlobalBool(UltraLightOnlyAnnounceFlag.Name)
1052 1053 1054
	}
}

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

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

1087 1088 1089 1090 1091
	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
1092 1093
}

1094
// setEtherbase retrieves the etherbase either from the directly specified
1095
// command line flags or from the keystore if CLI indexed.
1096
func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) {
1097 1098
	// Extract the current etherbase, new flag overriding legacy one
	var etherbase string
1099 1100 1101 1102
	if ctx.GlobalIsSet(LegacyMinerEtherbaseFlag.Name) {
		etherbase = ctx.GlobalString(LegacyMinerEtherbaseFlag.Name)
		log.Warn("The flag --etherbase is deprecated and will be removed in the future, please use --miner.etherbase")

1103 1104 1105 1106 1107 1108
	}
	if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) {
		etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name)
	}
	// Convert the etherbase into an address and configure it
	if etherbase != "" {
1109 1110 1111 1112 1113
		if ks != nil {
			account, err := MakeAddress(ks, etherbase)
			if err != nil {
				Fatalf("Invalid miner etherbase: %v", err)
			}
1114
			cfg.Miner.Etherbase = account.Address
1115 1116
		} else {
			Fatalf("No etherbase configured")
1117
		}
1118
	}
1119 1120
}

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

1139 1140 1141 1142 1143 1144 1145
func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
	setNodeKey(ctx, cfg)
	setNAT(ctx, cfg)
	setListenAddress(ctx, cfg)
	setBootstrapNodes(ctx, cfg)
	setBootstrapNodesV5(ctx, cfg)

1146
	lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light"
1147
	lightServer := (ctx.GlobalInt(LegacyLightServFlag.Name) != 0 || ctx.GlobalInt(LightServeFlag.Name) != 0)
1148

1149
	lightPeers := ctx.GlobalInt(LegacyLightPeersFlag.Name)
1150 1151 1152
	if ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
		lightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name)
	}
1153
	if lightClient && !ctx.GlobalIsSet(LegacyLightPeersFlag.Name) && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
1154 1155 1156 1157
		// dynamic default - for clients we use 1/10th of the default for servers
		lightPeers /= 10
	}

1158 1159
	if ctx.GlobalIsSet(MaxPeersFlag.Name) {
		cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
1160
		if lightServer && !ctx.GlobalIsSet(LegacyLightPeersFlag.Name) && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
1161 1162
			cfg.MaxPeers += lightPeers
		}
1163 1164 1165 1166
	} else {
		if lightServer {
			cfg.MaxPeers += lightPeers
		}
1167
		if lightClient && (ctx.GlobalIsSet(LegacyLightPeersFlag.Name) || ctx.GlobalIsSet(LightMaxPeersFlag.Name)) && cfg.MaxPeers < lightPeers {
1168 1169
			cfg.MaxPeers = lightPeers
		}
1170
	}
1171 1172 1173 1174 1175 1176 1177 1178 1179
	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)

1180 1181 1182
	if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) {
		cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name)
	}
1183
	if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient {
1184
		cfg.NoDiscovery = true
1185 1186
	}

1187 1188 1189
	// 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
1190
	forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name)
1191 1192 1193 1194
	if ctx.GlobalIsSet(DiscoveryV5Flag.Name) {
		cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name)
	} else if forceV5Discovery {
		cfg.DiscoveryV5 = true
1195
	}
1196

1197 1198 1199
	if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" {
		list, err := netutil.ParseNetlist(netrestrict)
		if err != nil {
1200
			Fatalf("Option %q: %v", NetrestrictFlag.Name, err)
1201
		}
1202
		cfg.NetRestrict = list
1203 1204
	}

1205
	if ctx.GlobalBool(DeveloperFlag.Name) {
1206 1207 1208 1209 1210
		// --dev mode can't use p2p networking.
		cfg.MaxPeers = 0
		cfg.ListenAddr = ":0"
		cfg.NoDiscovery = true
		cfg.DiscoveryV5 = false
1211 1212 1213
	}
}

1214 1215 1216 1217 1218
// 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)
1219
	setGraphQL(ctx, cfg)
1220 1221
	setWS(ctx, cfg)
	setNodeUserIdent(ctx, cfg)
1222
	setDataDir(ctx, cfg)
1223
	setSmartCard(ctx, cfg)
1224

1225 1226 1227 1228
	if ctx.GlobalIsSet(ExternalSignerFlag.Name) {
		cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name)
	}

1229 1230 1231 1232 1233 1234
	if ctx.GlobalIsSet(KeyStoreDirFlag.Name) {
		cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name)
	}
	if ctx.GlobalIsSet(LightKDFFlag.Name) {
		cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name)
	}
1235 1236 1237
	if ctx.GlobalIsSet(NoUSBFlag.Name) {
		cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name)
	}
1238 1239 1240
	if ctx.GlobalIsSet(InsecureUnlockAllowedFlag.Name) {
		cfg.InsecureUnlockAllowed = ctx.GlobalBool(InsecureUnlockAllowedFlag.Name)
	}
1241 1242
}

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

1263 1264 1265 1266 1267 1268
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
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278
	case (ctx.GlobalBool(LegacyTestnetFlag.Name) || ctx.GlobalBool(RopstenFlag.Name)) && cfg.DataDir == node.DefaultDataDir():
		// 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")
		}
1279
	case ctx.GlobalBool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir():
1280
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
1281
	case ctx.GlobalBool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
1282
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
1283 1284
	case ctx.GlobalBool(YoloV1Flag.Name) && cfg.DataDir == node.DefaultDataDir():
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "yolo-v1")
1285 1286 1287
	}
}

1288
func setGPO(ctx *cli.Context, cfg *gasprice.Config) {
1289 1290 1291 1292
	if ctx.GlobalIsSet(LegacyGpoBlocksFlag.Name) {
		cfg.Blocks = ctx.GlobalInt(LegacyGpoBlocksFlag.Name)
		log.Warn("The flag --gpoblocks is deprecated and will be removed in the future, please use --gpo.blocks")
	}
1293 1294 1295
	if ctx.GlobalIsSet(GpoBlocksFlag.Name) {
		cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name)
	}
1296 1297 1298 1299 1300

	if ctx.GlobalIsSet(LegacyGpoPercentileFlag.Name) {
		cfg.Percentile = ctx.GlobalInt(LegacyGpoPercentileFlag.Name)
		log.Warn("The flag --gpopercentile is deprecated and will be removed in the future, please use --gpo.percentile")
	}
1301 1302 1303 1304 1305
	if ctx.GlobalIsSet(GpoPercentileFlag.Name) {
		cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name)
	}
}

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 1350
func setEthash(ctx *cli.Context, cfg *eth.Config) {
	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 1381 1382
	if ctx.GlobalIsSet(LegacyMinerExtraDataFlag.Name) {
		cfg.ExtraData = []byte(ctx.GlobalString(LegacyMinerExtraDataFlag.Name))
		log.Warn("The flag --extradata is deprecated and will be removed in the future, please use --miner.extradata")
1383 1384 1385 1386
	}
	if ctx.GlobalIsSet(MinerExtraDataFlag.Name) {
		cfg.ExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name))
	}
1387 1388 1389
	if ctx.GlobalIsSet(LegacyMinerGasTargetFlag.Name) {
		cfg.GasFloor = ctx.GlobalUint64(LegacyMinerGasTargetFlag.Name)
		log.Warn("The flag --targetgaslimit is deprecated and will be removed in the future, please use --miner.gastarget")
1390 1391 1392 1393 1394 1395 1396
	}
	if ctx.GlobalIsSet(MinerGasTargetFlag.Name) {
		cfg.GasFloor = ctx.GlobalUint64(MinerGasTargetFlag.Name)
	}
	if ctx.GlobalIsSet(MinerGasLimitFlag.Name) {
		cfg.GasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name)
	}
1397 1398 1399
	if ctx.GlobalIsSet(LegacyMinerGasPriceFlag.Name) {
		cfg.GasPrice = GlobalBig(ctx, LegacyMinerGasPriceFlag.Name)
		log.Warn("The flag --gasprice is deprecated and will be removed in the future, please use --miner.gasprice")
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
	}
	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)
	}
}

1412
func setWhitelist(ctx *cli.Context, cfg *eth.Config) {
1413 1414 1415 1416 1417 1418 1419 1420 1421
	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)
1422
		}
1423 1424 1425 1426 1427 1428 1429 1430 1431
		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
1432 1433 1434
	}
}

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

			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
1467
		if ctx.GlobalIsSet(flag.GetName()) {
1468
			set = append(set, "--"+name)
1469 1470
		}
	}
1471
	if len(set) > 1 {
1472
		Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", "))
1473
	}
1474 1475
}

1476 1477
// SetShhConfig applies shh-related command line flags to the config.
func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
1478 1479
	if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) {
		cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name))
1480
	}
1481 1482
	if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) {
		cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name)
1483
	}
1484 1485 1486
	if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) {
		cfg.RestrictConnectionBetweenLightClients = true
	}
1487 1488
}

1489 1490 1491
// 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
1492
	CheckExclusive(ctx, DeveloperFlag, LegacyTestnetFlag, RopstenFlag, RinkebyFlag, GoerliFlag, YoloV1Flag)
1493
	CheckExclusive(ctx, LegacyLightServFlag, LightServeFlag, SyncModeFlag, "light")
1494
	CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
1495 1496 1497 1498 1499
	CheckExclusive(ctx, GCModeFlag, "archive", TxLookupLimitFlag)
	// todo(rjl493456442) make it available for les server
	// Ancient tx indices pruning is not available for les server now
	// since light client relies on the server for transaction status query.
	CheckExclusive(ctx, LegacyLightServFlag, LightServeFlag, TxLookupLimitFlag)
1500 1501 1502 1503
	var ks *keystore.KeyStore
	if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 {
		ks = keystores[0].(*keystore.KeyStore)
	}
1504 1505
	setEtherbase(ctx, ks, cfg)
	setGPO(ctx, &cfg.GPO)
1506
	setTxPool(ctx, &cfg.TxPool)
1507
	setEthash(ctx, cfg)
1508
	setMiner(ctx, &cfg.Miner)
1509
	setWhitelist(ctx, cfg)
1510
	setLes(ctx, cfg)
1511

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

1526 1527 1528
	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
	}
1529 1530 1531 1532 1533 1534
	if ctx.GlobalIsSet(GCModeFlag.Name) {
		cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"
	}
	if ctx.GlobalIsSet(CacheNoPrefetchFlag.Name) {
		cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name)
	}
1535 1536 1537
	if ctx.GlobalIsSet(TxLookupLimitFlag.Name) {
		cfg.TxLookupLimit = ctx.GlobalUint64(TxLookupLimitFlag.Name)
	}
1538 1539 1540
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
		cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
	}
1541
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
1542
		cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
1543
	}
1544 1545 1546
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) {
		cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100
	}
1547 1548 1549
	if !ctx.GlobalIsSet(SnapshotFlag.Name) {
		cfg.SnapshotCache = 0 // Disabled
	}
1550 1551 1552 1553 1554 1555 1556
	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)
	}
1557

1558 1559 1560 1561 1562 1563 1564
	if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) {
		cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name)
	}

	if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
		cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
	}
1565 1566 1567
	if ctx.GlobalIsSet(RPCGlobalGasCap.Name) {
		cfg.RPCGasCap = new(big.Int).SetUint64(ctx.GlobalUint64(RPCGlobalGasCap.Name))
	}
1568 1569 1570
	if ctx.GlobalIsSet(RPCGlobalTxFeeCap.Name) {
		cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCap.Name)
	}
1571 1572 1573 1574 1575 1576 1577 1578
	if ctx.GlobalIsSet(DNSDiscoveryFlag.Name) {
		urls := ctx.GlobalString(DNSDiscoveryFlag.Name)
		if urls == "" {
			cfg.DiscoveryURLs = []string{}
		} else {
			cfg.DiscoveryURLs = splitAndTrim(urls)
		}
	}
1579

1580
	// Override any default configs for hard coded networks.
1581
	switch {
1582
	case ctx.GlobalBool(LegacyTestnetFlag.Name) || ctx.GlobalBool(RopstenFlag.Name):
1583
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
1584
			cfg.NetworkId = 3
1585
		}
1586
		cfg.Genesis = core.DefaultRopstenGenesisBlock()
1587
		setDNSDiscoveryDefaults(cfg, params.RopstenGenesisHash)
1588 1589 1590 1591 1592
	case ctx.GlobalBool(RinkebyFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 4
		}
		cfg.Genesis = core.DefaultRinkebyGenesisBlock()
1593
		setDNSDiscoveryDefaults(cfg, params.RinkebyGenesisHash)
1594 1595 1596 1597 1598
	case ctx.GlobalBool(GoerliFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 5
		}
		cfg.Genesis = core.DefaultGoerliGenesisBlock()
1599
		setDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash)
1600 1601 1602 1603 1604
	case ctx.GlobalBool(YoloV1Flag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 133519467574833 // "yolov1"
		}
		cfg.Genesis = core.DefaultYoloV1GenesisBlock()
1605
	case ctx.GlobalBool(DeveloperFlag.Name):
1606 1607 1608
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 1337
		}
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
		// 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)
1628
		if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(LegacyMinerGasPriceFlag.Name) {
1629
			cfg.Miner.GasPrice = big.NewInt(1)
1630
		}
1631 1632
	default:
		if cfg.NetworkId == 1 {
1633
			setDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
1634 1635 1636 1637 1638 1639
		}
	}
}

// setDNSDiscoveryDefaults configures DNS discovery with the given URL if
// no URLs are set.
1640
func setDNSDiscoveryDefaults(cfg *eth.Config, genesis common.Hash) {
1641
	if cfg.DiscoveryURLs != nil {
1642 1643 1644
		return // already set through flags/config
	}

1645
	protocol := "all"
1646 1647 1648 1649 1650
	if cfg.SyncMode == downloader.LightSync {
		protocol = "les"
	}
	if url := params.KnownDNSNetwork(genesis, protocol); url != "" {
		cfg.DiscoveryURLs = []string{url}
1651
	}
1652
}
1653

1654 1655 1656 1657 1658 1659 1660
// 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)
		})
1661
	} else {
1662 1663 1664 1665
		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)
1666 1667 1668
				fullNode.AddLesServer(ls)
			}
			return fullNode, err
1669 1670 1671 1672
		})
	}
	if err != nil {
		Fatalf("Failed to register the Ethereum service: %v", err)
1673
	}
1674 1675
}

1676
// RegisterShhService configures Whisper and adds it to the given node.
1677 1678 1679 1680
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 {
1681
		Fatalf("Failed to register the Whisper service: %v", err)
1682
	}
1683 1684
}

1685
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
S
Sarlor 已提交
1686
// the given node.
1687 1688 1689 1690 1691 1692 1693 1694 1695
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)

1696
		// Let ethstats use whichever is not nil
1697 1698
		return ethstats.New(url, ethServ, lesServ)
	}); err != nil {
1699
		Fatalf("Failed to register the Ethereum Stats service: %v", err)
1700 1701 1702
	}
}

1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722
// 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)
	}
}

1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734
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 {
1735 1736
			tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name))

1737
			log.Info("Enabling metrics export to InfluxDB")
1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754

			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]
			}
1755 1756
		}
	}
1757 1758

	return tagsMap
1759 1760
}

1761
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
1762
func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
1763
	var (
1764
		cache   = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
1765
		handles = makeDatabaseHandles()
1766
	)
1767
	name := "chaindata"
1768
	if ctx.GlobalString(SyncModeFlag.Name) == "light" {
1769 1770
		name = "lightchaindata"
	}
1771
	chainDb, err := stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "")
1772
	if err != nil {
1773
		Fatalf("Could not open database: %v", err)
1774
	}
1775 1776 1777
	return chainDb
}

F
Felix Lange 已提交
1778 1779 1780
func MakeGenesis(ctx *cli.Context) *core.Genesis {
	var genesis *core.Genesis
	switch {
1781 1782
	case ctx.GlobalBool(LegacyTestnetFlag.Name) || ctx.GlobalBool(RopstenFlag.Name):
		genesis = core.DefaultRopstenGenesisBlock()
1783 1784
	case ctx.GlobalBool(RinkebyFlag.Name):
		genesis = core.DefaultRinkebyGenesisBlock()
1785 1786
	case ctx.GlobalBool(GoerliFlag.Name):
		genesis = core.DefaultGoerliGenesisBlock()
1787 1788
	case ctx.GlobalBool(YoloV1Flag.Name):
		genesis = core.DefaultYoloV1GenesisBlock()
1789 1790
	case ctx.GlobalBool(DeveloperFlag.Name):
		Fatalf("Developer chains are ephemeral")
F
Felix Lange 已提交
1791 1792 1793 1794
	}
	return genesis
}

1795
// MakeChain creates a chain manager from set command line flags.
1796
func MakeChain(ctx *cli.Context, stack *node.Node, readOnly bool) (chain *core.BlockChain, chainDb ethdb.Database) {
1797
	var err error
1798
	chainDb = MakeChainDatabase(ctx, stack)
F
Felix Lange 已提交
1799 1800 1801 1802
	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
	if err != nil {
		Fatalf("%v", err)
	}
1803 1804 1805 1806 1807 1808
	var engine consensus.Engine
	if config.Clique != nil {
		engine = clique.New(config.Clique, chainDb)
	} else {
		engine = ethash.NewFaker()
		if !ctx.GlobalBool(FakePoWFlag.Name) {
1809
			engine = ethash.New(ethash.Config{
1810 1811 1812 1813 1814 1815 1816 1817
				CacheDir:         stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir),
				CachesInMem:      eth.DefaultConfig.Ethash.CachesInMem,
				CachesOnDisk:     eth.DefaultConfig.Ethash.CachesOnDisk,
				CachesLockMmap:   eth.DefaultConfig.Ethash.CachesLockMmap,
				DatasetDir:       stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir),
				DatasetsInMem:    eth.DefaultConfig.Ethash.DatasetsInMem,
				DatasetsOnDisk:   eth.DefaultConfig.Ethash.DatasetsOnDisk,
				DatasetsLockMmap: eth.DefaultConfig.Ethash.DatasetsLockMmap,
1818
			}, nil, false)
1819 1820
		}
	}
1821 1822 1823 1824
	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
	}
	cache := &core.CacheConfig{
1825 1826 1827 1828 1829
		TrieCleanLimit:      eth.DefaultConfig.TrieCleanCache,
		TrieCleanNoPrefetch: ctx.GlobalBool(CacheNoPrefetchFlag.Name),
		TrieDirtyLimit:      eth.DefaultConfig.TrieDirtyCache,
		TrieDirtyDisabled:   ctx.GlobalString(GCModeFlag.Name) == "archive",
		TrieTimeLimit:       eth.DefaultConfig.TrieTimeout,
1830
		SnapshotLimit:       eth.DefaultConfig.SnapshotCache,
1831
	}
1832 1833 1834
	if !ctx.GlobalIsSet(SnapshotFlag.Name) {
		cache.SnapshotLimit = 0 // Disabled
	}
1835 1836
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
		cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
1837 1838
	}
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
1839
		cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
1840
	}
F
Felix Lange 已提交
1841
	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
1842 1843 1844 1845 1846 1847
	var limit *uint64
	if ctx.GlobalIsSet(TxLookupLimitFlag.Name) && !readOnly {
		l := ctx.GlobalUint64(TxLookupLimitFlag.Name)
		limit = &l
	}
	chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, limit)
O
obscuren 已提交
1848
	if err != nil {
F
Felix Lange 已提交
1849
		Fatalf("Can't create BlockChain: %v", err)
O
obscuren 已提交
1850
	}
1851
	return chain, chainDb
1852
}
1853 1854 1855 1856 1857 1858 1859 1860 1861

// 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
1862
	var preloads []string
1863 1864 1865 1866 1867 1868 1869

	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
}
1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893

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