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

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

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

88 89 90 91 92 93 94 95 96 97 98
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()
}

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

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

660
	// ATM the url is left to the user and deployment to
Z
CLI:  
zelig 已提交
661 662
	JSpathFlag = cli.StringFlag{
		Name:  "jspath",
663
		Usage: "JavaScript root path for `loadScript`",
Z
CLI:  
zelig 已提交
664 665
		Value: ".",
	}
666 667

	// Gas price oracle settings
668
	GpoBlocksFlag = cli.IntFlag{
669
		Name:  "gpo.blocks",
670
		Usage: "Number of recent blocks to check for gas prices",
671
		Value: ethconfig.Defaults.GPO.Blocks,
Z
zsfelfoldi 已提交
672
	}
673
	GpoPercentileFlag = cli.IntFlag{
674
		Name:  "gpo.percentile",
675
		Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices",
676
		Value: ethconfig.Defaults.GPO.Percentile,
Z
zsfelfoldi 已提交
677
	}
678 679 680
	GpoMaxGasPriceFlag = cli.Int64Flag{
		Name:  "gpo.maxprice",
		Usage: "Maximum gas price will be recommended by gpo",
681
		Value: ethconfig.Defaults.GPO.MaxPrice.Int64(),
682
	}
683 684 685

	// Metrics flags
	MetricsEnabledFlag = cli.BoolFlag{
686
		Name:  "metrics",
687 688
		Usage: "Enable metrics collection and reporting",
	}
689 690 691 692
	MetricsEnabledExpensiveFlag = cli.BoolFlag{
		Name:  "metrics.expensive",
		Usage: "Enable expensive metrics collection and reporting",
	}
693 694 695 696 697 698 699 700

	// 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",
701
		Value: metrics.DefaultConfig.HTTP,
702 703 704 705
	}
	MetricsPortFlag = cli.IntFlag{
		Name:  "metrics.port",
		Usage: "Metrics HTTP server listening port",
706
		Value: metrics.DefaultConfig.Port,
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",
715
		Value: metrics.DefaultConfig.InfluxDBEndpoint,
716 717 718 719
	}
	MetricsInfluxDBDatabaseFlag = cli.StringFlag{
		Name:  "metrics.influxdb.database",
		Usage: "InfluxDB database name to push reported metrics to",
720
		Value: metrics.DefaultConfig.InfluxDBDatabase,
721 722 723 724
	}
	MetricsInfluxDBUsernameFlag = cli.StringFlag{
		Name:  "metrics.influxdb.username",
		Usage: "Username to authorize access to the database",
725
		Value: metrics.DefaultConfig.InfluxDBUsername,
726 727 728 729
	}
	MetricsInfluxDBPasswordFlag = cli.StringFlag{
		Name:  "metrics.influxdb.password",
		Usage: "Password to authorize access to the database",
730
		Value: metrics.DefaultConfig.InfluxDBPassword,
731
	}
732 733 734
	// 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.
735
	// https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key
736 737 738
	MetricsInfluxDBTagsFlag = cli.StringFlag{
		Name:  "metrics.influxdb.tags",
		Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements",
739
		Value: metrics.DefaultConfig.InfluxDBTags,
740
	}
741 742 743 744 745 746 747 748 749 750
	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: "",
	}
751 752
)

753
// MakeDataDir retrieves the currently requested data directory, terminating
754
// if none (or the empty string) is specified. If the node is starting a testnet,
755
// then a subdirectory of the specified datadir will be used.
756
func MakeDataDir(ctx *cli.Context) string {
757
	if path := ctx.GlobalString(DataDirFlag.Name); path != "" {
758
		if ctx.GlobalBool(RopstenFlag.Name) {
759 760 761
			// Maintain compatibility with older Geth configurations storing the
			// Ropsten database in `testnet` instead of `ropsten`.
			return filepath.Join(path, "ropsten")
762
		}
763 764 765
		if ctx.GlobalBool(RinkebyFlag.Name) {
			return filepath.Join(path, "rinkeby")
		}
766 767 768
		if ctx.GlobalBool(GoerliFlag.Name) {
			return filepath.Join(path, "goerli")
		}
769 770
		if ctx.GlobalBool(YoloV3Flag.Name) {
			return filepath.Join(path, "yolo-v3")
771
		}
772
		return path
773
	}
774
	Fatalf("Cannot determine default data directory, please set manually (--datadir)")
775
	return ""
776 777
}

778
// setNodeKey creates a node key from set command line flags, either loading it
779 780
// 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.
781
func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
782 783 784
	var (
		hex  = ctx.GlobalString(NodeKeyHexFlag.Name)
		file = ctx.GlobalString(NodeKeyFileFlag.Name)
785 786
		key  *ecdsa.PrivateKey
		err  error
787
	)
788 789
	switch {
	case file != "" && hex != "":
790
		Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name)
791 792
	case file != "":
		if key, err = crypto.LoadECDSA(file); err != nil {
793
			Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err)
794
		}
795
		cfg.PrivateKey = key
796 797
	case hex != "":
		if key, err = crypto.HexToECDSA(hex); err != nil {
798
			Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err)
799
		}
800
		cfg.PrivateKey = key
801 802 803
	}
}

804 805
// setNodeUserIdent creates the user identifier from CLI flags.
func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
806
	if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 {
807
		cfg.UserIdent = identity
808 809 810
	}
}

811
// setBootstrapNodes creates a list of bootstrap nodes from the command line
812
// flags, reverting to pre-configured ones if none have been specified.
813
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
814
	urls := params.MainnetBootnodes
815
	switch {
816 817 818
	case ctx.GlobalIsSet(BootnodesFlag.Name):
		urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name))
	case ctx.GlobalBool(RopstenFlag.Name):
819
		urls = params.RopstenBootnodes
820 821
	case ctx.GlobalBool(RinkebyFlag.Name):
		urls = params.RinkebyBootnodes
822 823
	case ctx.GlobalBool(GoerliFlag.Name):
		urls = params.GoerliBootnodes
824 825
	case ctx.GlobalBool(YoloV3Flag.Name):
		urls = params.YoloV3Bootnodes
826 827
	case cfg.BootstrapNodes != nil:
		return // already set, don't apply defaults.
828 829
	}

830
	cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls))
831
	for _, url := range urls {
832
		if url != "" {
833
			node, err := enode.Parse(enode.ValidSchemes, url)
834 835
			if err != nil {
				log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
836
				continue
837 838
			}
			cfg.BootstrapNodes = append(cfg.BootstrapNodes, node)
839 840 841 842
		}
	}
}

843
// setBootstrapNodesV5 creates a list of bootstrap nodes from the command line
844
// flags, reverting to pre-configured ones if none have been specified.
845
func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
846
	urls := params.V5Bootnodes
847
	switch {
848 849
	case ctx.GlobalIsSet(BootnodesFlag.Name):
		urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name))
850
	case cfg.BootstrapNodesV5 != nil:
851
		return // already set, don't apply defaults.
852 853
	}

854
	cfg.BootstrapNodesV5 = make([]*enode.Node, 0, len(urls))
855
	for _, url := range urls {
856
		if url != "" {
857
			node, err := enode.Parse(enode.ValidSchemes, url)
858 859 860 861 862
			if err != nil {
				log.Error("Bootstrap URL invalid", "enode", url, "err", err)
				continue
			}
			cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node)
863 864 865 866
		}
	}
}

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

875 876 877 878 879 880 881 882
// 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
883 884 885
	}
}

886
// SplitAndTrim splits input separated by a comma
887
// and trims excessive white space from the substrings.
888
func SplitAndTrim(input string) (ret []string) {
889 890
	l := strings.Split(input, ",")
	for _, r := range l {
891
		if r = strings.TrimSpace(r); r != "" {
892 893
			ret = append(ret, r)
		}
894
	}
895
	return ret
896 897
}

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

	if ctx.GlobalIsSet(LegacyRPCPortFlag.Name) {
		cfg.HTTPPort = ctx.GlobalInt(LegacyRPCPortFlag.Name)
918
		log.Warn("The flag --rpcport is deprecated and will be removed June 2021, please use --http.port")
919
	}
920 921
	if ctx.GlobalIsSet(HTTPPortFlag.Name) {
		cfg.HTTPPort = ctx.GlobalInt(HTTPPortFlag.Name)
922
	}
923 924

	if ctx.GlobalIsSet(LegacyRPCCORSDomainFlag.Name) {
925
		cfg.HTTPCors = SplitAndTrim(ctx.GlobalString(LegacyRPCCORSDomainFlag.Name))
926
		log.Warn("The flag --rpccorsdomain is deprecated and will be removed June 2021, please use --http.corsdomain")
927 928
	}
	if ctx.GlobalIsSet(HTTPCORSDomainFlag.Name) {
929
		cfg.HTTPCors = SplitAndTrim(ctx.GlobalString(HTTPCORSDomainFlag.Name))
930 931 932
	}

	if ctx.GlobalIsSet(LegacyRPCApiFlag.Name) {
933
		cfg.HTTPModules = SplitAndTrim(ctx.GlobalString(LegacyRPCApiFlag.Name))
934
		log.Warn("The flag --rpcapi is deprecated and will be removed June 2021, please use --http.api")
935 936
	}
	if ctx.GlobalIsSet(HTTPApiFlag.Name) {
937
		cfg.HTTPModules = SplitAndTrim(ctx.GlobalString(HTTPApiFlag.Name))
938 939 940
	}

	if ctx.GlobalIsSet(LegacyRPCVirtualHostsFlag.Name) {
941
		cfg.HTTPVirtualHosts = SplitAndTrim(ctx.GlobalString(LegacyRPCVirtualHostsFlag.Name))
942
		log.Warn("The flag --rpcvhosts is deprecated and will be removed June 2021, please use --http.vhosts")
943 944
	}
	if ctx.GlobalIsSet(HTTPVirtualHostsFlag.Name) {
945
		cfg.HTTPVirtualHosts = SplitAndTrim(ctx.GlobalString(HTTPVirtualHostsFlag.Name))
946
	}
947 948 949 950

	if ctx.GlobalIsSet(HTTPPathPrefixFlag.Name) {
		cfg.HTTPPathPrefix = ctx.GlobalString(HTTPPathPrefixFlag.Name)
	}
951 952 953
	if ctx.GlobalIsSet(AllowUnprotectedTxs.Name) {
		cfg.AllowUnprotectedTxs = ctx.GlobalBool(AllowUnprotectedTxs.Name)
	}
954 955
}

956 957 958 959
// 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) {
960
		cfg.GraphQLCors = SplitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name))
961 962
	}
	if ctx.GlobalIsSet(GraphQLVirtualHostsFlag.Name) {
963
		cfg.GraphQLVirtualHosts = SplitAndTrim(ctx.GlobalString(GraphQLVirtualHostsFlag.Name))
964 965 966
	}
}

967
// setWS creates the WebSocket RPC listener interface string from the set
968
// command line flags, returning empty if the HTTP endpoint is disabled.
969 970 971 972 973 974 975 976 977 978
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)
	}
979

980
	if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) {
981
		cfg.WSOrigins = SplitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name))
982
	}
983

984
	if ctx.GlobalIsSet(WSApiFlag.Name) {
985
		cfg.WSModules = SplitAndTrim(ctx.GlobalString(WSApiFlag.Name))
986
	}
987 988 989 990

	if ctx.GlobalIsSet(WSPathPrefixFlag.Name) {
		cfg.WSPathPrefix = ctx.GlobalString(WSPathPrefixFlag.Name)
	}
991 992 993 994 995
}

// 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) {
996
	CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag)
997 998 999 1000 1001
	switch {
	case ctx.GlobalBool(IPCDisabledFlag.Name):
		cfg.IPCPath = ""
	case ctx.GlobalIsSet(IPCPathFlag.Name):
		cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name)
1002 1003 1004
	}
}

1005
// setLes configures the les server and ultra light client settings from the command line flags.
1006
func setLes(ctx *cli.Context, cfg *ethconfig.Config) {
1007 1008 1009 1010 1011
	if ctx.GlobalIsSet(LightServeFlag.Name) {
		cfg.LightServ = ctx.GlobalInt(LightServeFlag.Name)
	}
	if ctx.GlobalIsSet(LightIngressFlag.Name) {
		cfg.LightIngress = ctx.GlobalInt(LightIngressFlag.Name)
1012
	}
1013 1014
	if ctx.GlobalIsSet(LightEgressFlag.Name) {
		cfg.LightEgress = ctx.GlobalInt(LightEgressFlag.Name)
1015
	}
1016 1017
	if ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
		cfg.LightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name)
1018
	}
1019 1020
	if ctx.GlobalIsSet(UltraLightServersFlag.Name) {
		cfg.UltraLightServers = strings.Split(ctx.GlobalString(UltraLightServersFlag.Name), ",")
1021
	}
1022 1023
	if ctx.GlobalIsSet(UltraLightFractionFlag.Name) {
		cfg.UltraLightFraction = ctx.GlobalInt(UltraLightFractionFlag.Name)
1024
	}
1025
	if cfg.UltraLightFraction <= 0 && cfg.UltraLightFraction > 100 {
1026 1027
		log.Error("Ultra light fraction is invalid", "had", cfg.UltraLightFraction, "updated", ethconfig.Defaults.UltraLightFraction)
		cfg.UltraLightFraction = ethconfig.Defaults.UltraLightFraction
1028
	}
1029 1030
	if ctx.GlobalIsSet(UltraLightOnlyAnnounceFlag.Name) {
		cfg.UltraLightOnlyAnnounce = ctx.GlobalBool(UltraLightOnlyAnnounceFlag.Name)
1031
	}
1032 1033 1034
	if ctx.GlobalIsSet(LightNoPruneFlag.Name) {
		cfg.LightNoPrune = ctx.GlobalBool(LightNoPruneFlag.Name)
	}
1035 1036 1037
	if ctx.GlobalIsSet(LightNoSyncServeFlag.Name) {
		cfg.LightNoSyncServe = ctx.GlobalBool(LightNoSyncServeFlag.Name)
	}
1038 1039
}

1040
// MakeDatabaseHandles raises out the number of allowed file handles per process
1041
// for Geth and returns half of the allowance to assign to the database.
1042
func MakeDatabaseHandles() int {
1043
	limit, err := fdlimit.Maximum()
1044
	if err != nil {
1045
		Fatalf("Failed to retrieve file descriptor allowance: %v", err)
1046
	}
1047 1048
	raised, err := fdlimit.Raise(uint64(limit))
	if err != nil {
1049
		Fatalf("Failed to raise file descriptor allowance: %v", err)
1050
	}
1051
	return int(raised / 2) // Leave half for networking and other stuff
1052 1053
}

1054 1055
// MakeAddress converts an account specified directly as a hex encoded string or
// a key index in the key store to an internal account representation.
1056
func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
1057 1058
	// If the specified account is a valid address, return it
	if common.IsHexAddress(account) {
F
Felix Lange 已提交
1059
		return accounts.Account{Address: common.HexToAddress(account)}, nil
1060 1061 1062
	}
	// Otherwise try to interpret the account as a keystore index
	index, err := strconv.Atoi(account)
1063
	if err != nil || index < 0 {
F
Felix Lange 已提交
1064
		return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account)
1065
	}
1066 1067 1068 1069 1070 1071
	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("-------------------------------------------------------------------")

1072 1073 1074 1075 1076
	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
1077 1078
}

1079
// setEtherbase retrieves the etherbase either from the directly specified
1080
// command line flags or from the keystore if CLI indexed.
1081
func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *ethconfig.Config) {
1082
	// Extract the current etherbase
1083 1084 1085 1086 1087 1088
	var etherbase string
	if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) {
		etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name)
	}
	// Convert the etherbase into an address and configure it
	if etherbase != "" {
1089 1090 1091 1092 1093
		if ks != nil {
			account, err := MakeAddress(ks, etherbase)
			if err != nil {
				Fatalf("Invalid miner etherbase: %v", err)
			}
1094
			cfg.Miner.Etherbase = account.Address
1095 1096
		} else {
			Fatalf("No etherbase configured")
1097
		}
1098
	}
1099 1100
}

1101
// MakePasswordList reads password lines from the file specified by the global --password flag.
1102
func MakePasswordList(ctx *cli.Context) []string {
1103 1104 1105 1106 1107 1108
	path := ctx.GlobalString(PasswordFileFlag.Name)
	if path == "" {
		return nil
	}
	text, err := ioutil.ReadFile(path)
	if err != nil {
1109
		Fatalf("Failed to read password file: %v", err)
1110 1111 1112 1113 1114
	}
	lines := strings.Split(string(text), "\n")
	// Sanitise DOS line endings.
	for i := range lines {
		lines[i] = strings.TrimRight(lines[i], "\r")
1115
	}
1116
	return lines
1117 1118
}

1119 1120 1121 1122 1123 1124 1125
func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
	setNodeKey(ctx, cfg)
	setNAT(ctx, cfg)
	setListenAddress(ctx, cfg)
	setBootstrapNodes(ctx, cfg)
	setBootstrapNodesV5(ctx, cfg)

1126
	lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light"
1127
	lightServer := (ctx.GlobalInt(LightServeFlag.Name) != 0)
1128

1129 1130
	lightPeers := ctx.GlobalInt(LightMaxPeersFlag.Name)
	if lightClient && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
1131 1132 1133 1134
		// dynamic default - for clients we use 1/10th of the default for servers
		lightPeers /= 10
	}

1135 1136
	if ctx.GlobalIsSet(MaxPeersFlag.Name) {
		cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
1137
		if lightServer && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
1138 1139
			cfg.MaxPeers += lightPeers
		}
1140 1141 1142 1143
	} else {
		if lightServer {
			cfg.MaxPeers += lightPeers
		}
1144
		if lightClient && ctx.GlobalIsSet(LightMaxPeersFlag.Name) && cfg.MaxPeers < lightPeers {
1145 1146
			cfg.MaxPeers = lightPeers
		}
1147
	}
1148 1149 1150 1151 1152 1153 1154 1155 1156
	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)

1157 1158 1159
	if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) {
		cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name)
	}
1160
	if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient {
1161
		cfg.NoDiscovery = true
1162 1163
	}

1164 1165 1166
	// 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
1167
	forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name)
1168 1169 1170 1171
	if ctx.GlobalIsSet(DiscoveryV5Flag.Name) {
		cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name)
	} else if forceV5Discovery {
		cfg.DiscoveryV5 = true
1172
	}
1173

1174 1175 1176
	if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" {
		list, err := netutil.ParseNetlist(netrestrict)
		if err != nil {
1177
			Fatalf("Option %q: %v", NetrestrictFlag.Name, err)
1178
		}
1179
		cfg.NetRestrict = list
1180 1181
	}

1182
	if ctx.GlobalBool(DeveloperFlag.Name) {
1183 1184 1185 1186 1187
		// --dev mode can't use p2p networking.
		cfg.MaxPeers = 0
		cfg.ListenAddr = ":0"
		cfg.NoDiscovery = true
		cfg.DiscoveryV5 = false
1188 1189 1190
	}
}

1191 1192 1193 1194 1195
// 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)
1196
	setGraphQL(ctx, cfg)
1197 1198
	setWS(ctx, cfg)
	setNodeUserIdent(ctx, cfg)
1199
	setDataDir(ctx, cfg)
1200
	setSmartCard(ctx, cfg)
1201

1202 1203 1204 1205
	if ctx.GlobalIsSet(ExternalSignerFlag.Name) {
		cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name)
	}

1206 1207 1208 1209 1210 1211
	if ctx.GlobalIsSet(KeyStoreDirFlag.Name) {
		cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name)
	}
	if ctx.GlobalIsSet(LightKDFFlag.Name) {
		cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name)
	}
1212
	if ctx.GlobalIsSet(NoUSBFlag.Name) || cfg.NoUSB {
1213
		log.Warn("Option nousb is deprecated and USB is deactivated by default. Use --usb to enable")
1214
	}
1215 1216 1217
	if ctx.GlobalIsSet(USBFlag.Name) {
		cfg.USB = ctx.GlobalBool(USBFlag.Name)
	}
1218 1219 1220
	if ctx.GlobalIsSet(InsecureUnlockAllowedFlag.Name) {
		cfg.InsecureUnlockAllowed = ctx.GlobalBool(InsecureUnlockAllowedFlag.Name)
	}
1221 1222
}

1223 1224 1225 1226 1227 1228 1229 1230 1231
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 {
1232
		log.Info("Smartcard socket not found, disabling", "err", err)
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
		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
}

1243 1244 1245 1246 1247 1248
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
1249
	case ctx.GlobalBool(RopstenFlag.Name) && cfg.DataDir == node.DefaultDataDir():
1250 1251 1252 1253 1254 1255 1256 1257 1258
		// 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")
		}
1259 1260

		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten")
1261
	case ctx.GlobalBool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir():
1262
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
1263
	case ctx.GlobalBool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
1264
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
1265
	case ctx.GlobalBool(YoloV3Flag.Name) && cfg.DataDir == node.DefaultDataDir():
1266
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "yolo-v3")
1267 1268 1269
	}
}

1270 1271 1272 1273
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 {
1274 1275
		cfg.Blocks = ethconfig.LightClientGPO.Blocks
		cfg.Percentile = ethconfig.LightClientGPO.Percentile
1276
	}
1277 1278 1279 1280 1281 1282
	if ctx.GlobalIsSet(GpoBlocksFlag.Name) {
		cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name)
	}
	if ctx.GlobalIsSet(GpoPercentileFlag.Name) {
		cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name)
	}
1283 1284 1285
	if ctx.GlobalIsSet(GpoMaxGasPriceFlag.Name) {
		cfg.MaxPrice = big.NewInt(ctx.GlobalInt64(GpoMaxGasPriceFlag.Name))
	}
1286 1287
}

1288
func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) {
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
	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))
			}
		}
	}
1299 1300 1301
	if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) {
		cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name)
	}
1302 1303 1304 1305 1306 1307
	if ctx.GlobalIsSet(TxPoolJournalFlag.Name) {
		cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name)
	}
	if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) {
		cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name)
	}
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330
	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)
	}
}

1331
func setEthash(ctx *cli.Context, cfg *ethconfig.Config) {
1332
	if ctx.GlobalIsSet(EthashCacheDirFlag.Name) {
1333
		cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name)
1334 1335
	}
	if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) {
1336
		cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name)
1337 1338
	}
	if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) {
1339
		cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name)
1340 1341
	}
	if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) {
1342
		cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name)
1343
	}
1344 1345 1346
	if ctx.GlobalIsSet(EthashCachesLockMmapFlag.Name) {
		cfg.Ethash.CachesLockMmap = ctx.GlobalBool(EthashCachesLockMmapFlag.Name)
	}
1347
	if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) {
1348
		cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name)
1349 1350
	}
	if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) {
1351
		cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name)
1352
	}
1353 1354 1355
	if ctx.GlobalIsSet(EthashDatasetsLockMmapFlag.Name) {
		cfg.Ethash.DatasetsLockMmap = ctx.GlobalBool(EthashDatasetsLockMmapFlag.Name)
	}
1356 1357
}

1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374
func setMiner(ctx *cli.Context, cfg *miner.Config) {
	if ctx.GlobalIsSet(MinerNotifyFlag.Name) {
		cfg.Notify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",")
	}
	if ctx.GlobalIsSet(MinerExtraDataFlag.Name) {
		cfg.ExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name))
	}
	if ctx.GlobalIsSet(MinerGasTargetFlag.Name) {
		cfg.GasFloor = ctx.GlobalUint64(MinerGasTargetFlag.Name)
	}
	if ctx.GlobalIsSet(MinerGasLimitFlag.Name) {
		cfg.GasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name)
	}
	if ctx.GlobalIsSet(MinerGasPriceFlag.Name) {
		cfg.GasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name)
	}
	if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) {
1375
		cfg.Recommit = ctx.GlobalDuration(MinerRecommitIntervalFlag.Name)
1376 1377
	}
	if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) {
1378
		cfg.Noverify = ctx.GlobalBool(MinerNoVerfiyFlag.Name)
1379 1380 1381
	}
}

1382
func setWhitelist(ctx *cli.Context, cfg *ethconfig.Config) {
1383 1384 1385 1386 1387 1388 1389 1390 1391
	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)
1392
		}
1393 1394 1395 1396 1397 1398 1399 1400 1401
		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
1402 1403 1404
	}
}

1405
// CheckExclusive verifies that only a single instance of the provided flags was
1406 1407
// set by the user. Each flag might optionally be followed by a string type to
// specialize it further.
1408
func CheckExclusive(ctx *cli.Context, args ...interface{}) {
1409
	set := make([]string, 0, 1)
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
	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:
1422
				// Extended flag check, make sure value set doesn't conflict with passed in option
1423 1424
				if ctx.GlobalString(flag.GetName()) == option {
					name += "=" + option
1425
					set = append(set, "--"+name)
1426
				}
1427
				// shift arguments and continue
1428
				i++
1429
				continue
1430 1431 1432 1433 1434 1435 1436

			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
1437
		if ctx.GlobalIsSet(flag.GetName()) {
1438
			set = append(set, "--"+name)
1439 1440
		}
	}
1441
	if len(set) > 1 {
1442
		Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", "))
1443
	}
1444 1445 1446
}

// SetEthConfig applies eth-related command line flags to the config.
1447
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
1448
	// Avoid conflicting network flags
1449 1450
	CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, YoloV3Flag)
	CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light")
1451
	CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
1452 1453 1454 1455 1456
	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 {
1457 1458
		log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited")
	}
1459 1460 1461 1462
	var ks *keystore.KeyStore
	if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 {
		ks = keystores[0].(*keystore.KeyStore)
	}
1463
	setEtherbase(ctx, ks, cfg)
1464
	setGPO(ctx, &cfg.GPO, ctx.GlobalString(SyncModeFlag.Name) == "light")
1465
	setTxPool(ctx, &cfg.TxPool)
1466
	setEthash(ctx, cfg)
1467
	setMiner(ctx, &cfg.Miner)
1468
	setWhitelist(ctx, cfg)
1469
	setLes(ctx, cfg)
1470

1471
	if ctx.GlobalIsSet(SyncModeFlag.Name) {
1472 1473 1474
		cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)
	}
	if ctx.GlobalIsSet(NetworkIdFlag.Name) {
1475
		cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name)
1476
	}
1477 1478
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) {
		cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
1479
	}
1480
	cfg.DatabaseHandles = MakeDatabaseHandles()
1481 1482 1483
	if ctx.GlobalIsSet(AncientFlag.Name) {
		cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name)
	}
1484

1485 1486 1487
	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
	}
1488 1489 1490 1491 1492 1493
	if ctx.GlobalIsSet(GCModeFlag.Name) {
		cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"
	}
	if ctx.GlobalIsSet(CacheNoPrefetchFlag.Name) {
		cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name)
	}
1494 1495 1496 1497 1498 1499
	// 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")
	}
1500 1501 1502
	if ctx.GlobalIsSet(TxLookupLimitFlag.Name) {
		cfg.TxLookupLimit = ctx.GlobalUint64(TxLookupLimitFlag.Name)
	}
1503 1504 1505
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
		cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
	}
1506 1507 1508 1509 1510 1511
	if ctx.GlobalIsSet(CacheTrieJournalFlag.Name) {
		cfg.TrieCleanCacheJournal = ctx.GlobalString(CacheTrieJournalFlag.Name)
	}
	if ctx.GlobalIsSet(CacheTrieRejournalFlag.Name) {
		cfg.TrieCleanCacheRejournal = ctx.GlobalDuration(CacheTrieRejournalFlag.Name)
	}
1512
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
1513
		cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
1514
	}
1515 1516 1517
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) {
		cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100
	}
1518
	if !ctx.GlobalBool(SnapshotFlag.Name) {
1519 1520 1521 1522 1523 1524 1525
		// 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
		}
1526
	}
1527 1528 1529 1530 1531 1532 1533
	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)
	}
1534

1535 1536 1537 1538 1539 1540 1541
	if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) {
		cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name)
	}

	if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
		cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
	}
1542 1543
	if ctx.GlobalIsSet(RPCGlobalGasCapFlag.Name) {
		cfg.RPCGasCap = ctx.GlobalUint64(RPCGlobalGasCapFlag.Name)
1544 1545 1546 1547 1548
	}
	if cfg.RPCGasCap != 0 {
		log.Info("Set global gas cap", "cap", cfg.RPCGasCap)
	} else {
		log.Info("Global gas cap disabled")
1549
	}
1550 1551
	if ctx.GlobalIsSet(RPCGlobalTxFeeCapFlag.Name) {
		cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCapFlag.Name)
1552
	}
1553
	if ctx.GlobalIsSet(NoDiscoverFlag.Name) {
1554
		cfg.EthDiscoveryURLs, cfg.SnapDiscoveryURLs = []string{}, []string{}
1555
	} else if ctx.GlobalIsSet(DNSDiscoveryFlag.Name) {
1556 1557
		urls := ctx.GlobalString(DNSDiscoveryFlag.Name)
		if urls == "" {
1558
			cfg.EthDiscoveryURLs = []string{}
1559
		} else {
1560
			cfg.EthDiscoveryURLs = SplitAndTrim(urls)
1561 1562
		}
	}
1563
	// Override any default configs for hard coded networks.
1564
	switch {
1565 1566 1567 1568 1569 1570
	case ctx.GlobalBool(MainnetFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 1
		}
		cfg.Genesis = core.DefaultGenesisBlock()
		SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
1571
	case ctx.GlobalBool(RopstenFlag.Name):
1572
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
1573
			cfg.NetworkId = 3
1574
		}
1575
		cfg.Genesis = core.DefaultRopstenGenesisBlock()
1576
		SetDNSDiscoveryDefaults(cfg, params.RopstenGenesisHash)
1577 1578 1579 1580 1581
	case ctx.GlobalBool(RinkebyFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 4
		}
		cfg.Genesis = core.DefaultRinkebyGenesisBlock()
1582
		SetDNSDiscoveryDefaults(cfg, params.RinkebyGenesisHash)
1583 1584 1585 1586 1587
	case ctx.GlobalBool(GoerliFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 5
		}
		cfg.Genesis = core.DefaultGoerliGenesisBlock()
1588
		SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash)
1589
	case ctx.GlobalBool(YoloV3Flag.Name):
1590
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
1591
			cfg.NetworkId = new(big.Int).SetBytes([]byte("yolov3x")).Uint64() // "yolov3x"
1592
		}
1593
		cfg.Genesis = core.DefaultYoloV3GenesisBlock()
1594
	case ctx.GlobalBool(DeveloperFlag.Name):
1595 1596 1597
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 1337
		}
1598 1599
		// Create new developer account or reuse existing one
		var (
1600 1601 1602
			developer  accounts.Account
			passphrase string
			err        error
1603
		)
1604 1605 1606 1607 1608 1609 1610 1611 1612 1613
		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 {
1614 1615
			developer = ks.Accounts()[0]
		} else {
1616
			developer, err = ks.NewAccount(passphrase)
1617 1618 1619 1620
			if err != nil {
				Fatalf("Failed to create developer account: %v", err)
			}
		}
1621
		if err := ks.Unlock(developer, passphrase); err != nil {
1622 1623 1624 1625
			Fatalf("Failed to unlock developer account: %v", err)
		}
		log.Info("Using developer account", "address", developer.Address)

1626
		// Create a new developer genesis block or reuse existing one
1627
		cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address)
1628 1629 1630
		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.
1631
			chaindb := MakeChainDatabase(ctx, stack, true)
1632 1633 1634 1635 1636
			if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) {
				cfg.Genesis = nil // fallback to db content
			}
			chaindb.Close()
		}
1637
		if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) {
1638
			cfg.Miner.GasPrice = big.NewInt(1)
1639
		}
1640 1641
	default:
		if cfg.NetworkId == 1 {
1642
			SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
1643 1644 1645 1646
		}
	}
}

1647
// SetDNSDiscoveryDefaults configures DNS discovery with the given URL if
1648
// no URLs are set.
1649
func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) {
1650
	if cfg.EthDiscoveryURLs != nil {
1651 1652
		return // already set through flags/config
	}
1653
	protocol := "all"
1654 1655 1656 1657
	if cfg.SyncMode == downloader.LightSync {
		protocol = "les"
	}
	if url := params.KnownDNSNetwork(genesis, protocol); url != "" {
1658 1659 1660 1661 1662 1663
		cfg.EthDiscoveryURLs = []string{url}
	}
	if cfg.SyncMode == downloader.SnapSync {
		if url := params.KnownDNSNetwork(genesis, "snap"); url != "" {
			cfg.SnapDiscoveryURLs = []string{url}
		}
1664
	}
1665
}
1666

1667
// RegisterEthService adds an Ethereum client to the stack.
1668
func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) ethapi.Backend {
1669
	if cfg.SyncMode == downloader.LightSync {
R
rene 已提交
1670 1671 1672 1673
		backend, err := les.New(stack, cfg)
		if err != nil {
			Fatalf("Failed to register the Ethereum service: %v", err)
		}
1674
		stack.RegisterAPIs(tracers.APIs(backend.ApiBackend))
R
rene 已提交
1675
		return backend.ApiBackend
1676 1677 1678 1679 1680 1681 1682
	}
	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 已提交
1683
		if err != nil {
1684
			Fatalf("Failed to create the LES server: %v", err)
R
rene 已提交
1685
		}
1686
	}
1687
	stack.RegisterAPIs(tracers.APIs(backend.APIBackend))
1688
	return backend.APIBackend
1689 1690
}

1691
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
S
Sarlor 已提交
1692
// the given node.
R
rene 已提交
1693 1694
func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url string) {
	if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil {
1695
		Fatalf("Failed to register the Ethereum Stats service: %v", err)
1696 1697 1698
	}
}

1699
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
R
rene 已提交
1700 1701
func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, cfg node.Config) {
	if err := graphql.New(stack, backend, cfg.GraphQLCors, cfg.GraphQLVirtualHosts); err != nil {
1702 1703 1704 1705
		Fatalf("Failed to register the GraphQL service: %v", err)
	}
}

1706 1707 1708
func SetupMetrics(ctx *cli.Context) {
	if metrics.Enabled {
		log.Info("Enabling metrics collection")
1709

1710 1711 1712 1713 1714 1715 1716 1717 1718
		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 {
1719 1720
			tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name))

1721
			log.Info("Enabling metrics export to InfluxDB")
1722 1723 1724

			go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap)
		}
1725 1726 1727 1728 1729 1730

		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)
		}
1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744
	}
}

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]
			}
1745 1746
		}
	}
1747 1748

	return tagsMap
1749 1750
}

1751
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
1752
func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.Database {
1753
	var (
1754
		cache   = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
1755
		handles = MakeDatabaseHandles()
1756 1757 1758

		err     error
		chainDb ethdb.Database
1759
	)
1760
	if ctx.GlobalString(SyncModeFlag.Name) == "light" {
1761
		name := "lightchaindata"
1762
		chainDb, err = stack.OpenDatabase(name, cache, handles, "", readonly)
1763 1764
	} else {
		name := "chaindata"
1765
		chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly)
1766
	}
1767
	if err != nil {
1768
		Fatalf("Could not open database: %v", err)
1769
	}
1770 1771 1772
	return chainDb
}

F
Felix Lange 已提交
1773 1774 1775
func MakeGenesis(ctx *cli.Context) *core.Genesis {
	var genesis *core.Genesis
	switch {
1776 1777
	case ctx.GlobalBool(MainnetFlag.Name):
		genesis = core.DefaultGenesisBlock()
1778
	case ctx.GlobalBool(RopstenFlag.Name):
1779
		genesis = core.DefaultRopstenGenesisBlock()
1780 1781
	case ctx.GlobalBool(RinkebyFlag.Name):
		genesis = core.DefaultRinkebyGenesisBlock()
1782 1783
	case ctx.GlobalBool(GoerliFlag.Name):
		genesis = core.DefaultGoerliGenesisBlock()
1784 1785
	case ctx.GlobalBool(YoloV3Flag.Name):
		genesis = core.DefaultYoloV3GenesisBlock()
1786 1787
	case ctx.GlobalBool(DeveloperFlag.Name):
		Fatalf("Developer chains are ephemeral")
F
Felix Lange 已提交
1788 1789 1790 1791
	}
	return genesis
}

1792
// MakeChain creates a chain manager from set command line flags.
1793
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
1794
	var err error
1795
	chainDb = MakeChainDatabase(ctx, stack, false) // TODO(rjl493456442) support read-only database
F
Felix Lange 已提交
1796 1797 1798 1799
	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
	if err != nil {
		Fatalf("%v", err)
	}
1800 1801 1802 1803 1804 1805
	var engine consensus.Engine
	if config.Clique != nil {
		engine = clique.New(config.Clique, chainDb)
	} else {
		engine = ethash.NewFaker()
		if !ctx.GlobalBool(FakePoWFlag.Name) {
1806
			engine = ethash.New(ethash.Config{
1807 1808 1809 1810 1811 1812 1813 1814
				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,
1815
			}, nil, false)
1816 1817
		}
	}
1818 1819 1820 1821
	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
	}
	cache := &core.CacheConfig{
1822
		TrieCleanLimit:      ethconfig.Defaults.TrieCleanCache,
1823
		TrieCleanNoPrefetch: ctx.GlobalBool(CacheNoPrefetchFlag.Name),
1824
		TrieDirtyLimit:      ethconfig.Defaults.TrieDirtyCache,
1825
		TrieDirtyDisabled:   ctx.GlobalString(GCModeFlag.Name) == "archive",
1826 1827
		TrieTimeLimit:       ethconfig.Defaults.TrieTimeout,
		SnapshotLimit:       ethconfig.Defaults.SnapshotCache,
1828 1829 1830 1831 1832
		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")
1833
	}
1834
	if !ctx.GlobalBool(SnapshotFlag.Name) {
1835 1836
		cache.SnapshotLimit = 0 // Disabled
	}
1837 1838
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
		cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
1839 1840
	}
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
1841
		cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
1842
	}
F
Felix Lange 已提交
1843
	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
1844 1845 1846 1847

	// 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 已提交
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

	for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") {
1865
		preloads = append(preloads, strings.TrimSpace(file))
1866 1867 1868
	}
	return preloads
}
1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892

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