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

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

64 65 66 67 68
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:
69
	{{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
70 71 72 73 74 75 76
	{{end}}{{end}}{{if .categorizedFlags}}
{{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS:
{{range $categorized.Flags}}{{"\t"}}{{.}}
{{end}}
{{end}}{{end}}`
)

77 78 79 80 81 82 83 84 85 86 87 88 89 90
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}}
`

91
	cli.CommandHelpTemplate = CommandHelpTemplate
92 93
}

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

109 110 111 112 113 114 115 116 117
// 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
118
	DataDirFlag = DirectoryFlag{
119
		Name:  "datadir",
120
		Usage: "Data directory for the databases and keystore",
121
		Value: DirectoryString{node.DefaultDataDir()},
122
	}
K
Kobi Gurkan 已提交
123 124 125 126
	KeyStoreDirFlag = DirectoryFlag{
		Name:  "keystore",
		Usage: "Directory for the keystore (default = inside the datadir)",
	}
127 128
	NoUSBFlag = cli.BoolFlag{
		Name:  "nousb",
O
Oli Bye 已提交
129
		Usage: "Disables monitoring for and managing USB hardware wallets",
130
	}
131
	NetworkIdFlag = cli.Uint64Flag{
Z
zelig 已提交
132
		Name:  "networkid",
133
		Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)",
134
		Value: eth.DefaultConfig.NetworkId,
Z
zelig 已提交
135
	}
136
	TestnetFlag = cli.BoolFlag{
137
		Name:  "testnet",
138
		Usage: "Ropsten network: pre-configured proof-of-work test network",
139
	}
140 141 142 143
	RinkebyFlag = cli.BoolFlag{
		Name:  "rinkeby",
		Usage: "Rinkeby network: pre-configured proof-of-authority test network",
	}
144 145 146 147
	GoerliFlag = cli.BoolFlag{
		Name:  "goerli",
		Usage: "Görli network: pre-configured proof-of-authority test network",
	}
148 149 150 151
	ConstantinopleOverrideFlag = cli.Uint64Flag{
		Name:  "override.constantinople",
		Usage: "Manually specify constantinople fork-block, overriding the bundled setting",
	}
152
	DeveloperFlag = cli.BoolFlag{
153
		Name:  "dev",
154 155 156 157 158
		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)",
159
	}
160 161
	IdentityFlag = cli.StringFlag{
		Name:  "identity",
162
		Usage: "Custom node name",
163
	}
Z
zelig 已提交
164 165 166
	DocRootFlag = DirectoryFlag{
		Name:  "docroot",
		Usage: "Document Root for HTTPClient file scheme",
167
		Value: DirectoryString{homeDir()},
Z
zelig 已提交
168
	}
169 170 171 172
	ExitWhenSyncedFlag = cli.BoolFlag{
		Name:  "exitwhensynced",
		Usage: "Exists syncing after block synchronisation",
	}
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
	ULCModeConfigFlag = cli.StringFlag{
		Name:  "ulc.config",
		Usage: "Config file to use for ultra light client mode",
	}
	OnlyAnnounceModeFlag = cli.BoolFlag{
		Name:  "ulc.onlyannounce",
		Usage: "ULC server sends announcements only",
	}
	ULCMinTrustedFractionFlag = cli.IntFlag{
		Name:  "ulc.fraction",
		Usage: "Minimum % of trusted ULC servers required to announce a new head",
	}
	ULCTrustedNodesFlag = cli.StringFlag{
		Name:  "ulc.trusted",
		Usage: "List of trusted ULC servers",
	}
189 190 191 192 193 194
	defaultSyncMode = eth.DefaultConfig.SyncMode
	SyncModeFlag    = TextMarshalerFlag{
		Name:  "syncmode",
		Usage: `Blockchain sync mode ("fast", "full", or "light")`,
		Value: &defaultSyncMode,
	}
195 196 197 198 199
	GCModeFlag = cli.StringFlag{
		Name:  "gcmode",
		Usage: `Blockchain garbage collection mode ("full", "archive")`,
		Value: "full",
	}
200 201 202 203 204 205 206 207
	LightServFlag = cli.IntFlag{
		Name:  "lightserv",
		Usage: "Maximum percentage of time allowed for serving LES requests (0-90)",
		Value: 0,
	}
	LightPeersFlag = cli.IntFlag{
		Name:  "lightpeers",
		Usage: "Maximum number of LES client peers",
208
		Value: eth.DefaultConfig.LightPeers,
209
	}
210 211
	LightKDFFlag = cli.BoolFlag{
		Name:  "lightkdf",
212
		Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
213
	}
214 215 216 217
	WhitelistFlag = cli.StringFlag{
		Name:  "whitelist",
		Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)",
	}
218 219
	// Dashboard settings
	DashboardEnabledFlag = cli.BoolFlag{
220
		Name:  metrics.DashboardEnabledFlag,
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
		Usage: "Enable the dashboard",
	}
	DashboardAddrFlag = cli.StringFlag{
		Name:  "dashboard.addr",
		Usage: "Dashboard listening interface",
		Value: dashboard.DefaultConfig.Host,
	}
	DashboardPortFlag = cli.IntFlag{
		Name:  "dashboard.host",
		Usage: "Dashboard listening port",
		Value: dashboard.DefaultConfig.Port,
	}
	DashboardRefreshFlag = cli.DurationFlag{
		Name:  "dashboard.refresh",
		Usage: "Dashboard metrics collection refresh rate",
		Value: dashboard.DefaultConfig.Refresh,
	}
238 239 240 241 242 243 244 245
	// 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)",
246
		Value: eth.DefaultConfig.Ethash.CachesInMem,
247 248 249 250
	}
	EthashCachesOnDiskFlag = cli.IntFlag{
		Name:  "ethash.cachesondisk",
		Usage: "Number of recent ethash caches to keep on disk (16MB each)",
251
		Value: eth.DefaultConfig.Ethash.CachesOnDisk,
252 253 254 255
	}
	EthashDatasetDirFlag = DirectoryFlag{
		Name:  "ethash.dagdir",
		Usage: "Directory to store the ethash mining DAGs (default = inside home folder)",
256
		Value: DirectoryString{eth.DefaultConfig.Ethash.DatasetDir},
257 258 259 260
	}
	EthashDatasetsInMemoryFlag = cli.IntFlag{
		Name:  "ethash.dagsinmem",
		Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
261
		Value: eth.DefaultConfig.Ethash.DatasetsInMem,
262 263 264 265
	}
	EthashDatasetsOnDiskFlag = cli.IntFlag{
		Name:  "ethash.dagsondisk",
		Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
266
		Value: eth.DefaultConfig.Ethash.DatasetsOnDisk,
267 268
	}
	// Transaction pool settings
269 270 271 272
	TxPoolLocalsFlag = cli.StringFlag{
		Name:  "txpool.locals",
		Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)",
	}
273 274 275 276
	TxPoolNoLocalsFlag = cli.BoolFlag{
		Name:  "txpool.nolocals",
		Usage: "Disables price exemptions for locally submitted transactions",
	}
277 278 279 280 281 282 283 284 285 286
	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,
	}
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
	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,
	}
322 323 324
	// Performance tuning settings
	CacheFlag = cli.IntFlag{
		Name:  "cache",
325 326 327 328 329 330
		Usage: "Megabytes of memory allocated to internal caching",
		Value: 1024,
	}
	CacheDatabaseFlag = cli.IntFlag{
		Name:  "cache.database",
		Usage: "Percentage of cache memory allowance to use for database io",
331 332 333 334
		Value: 50,
	}
	CacheTrieFlag = cli.IntFlag{
		Name:  "cache.trie",
335
		Usage: "Percentage of cache memory allowance to use for trie caching (default = 25% full mode, 50% archive mode)",
336
		Value: 25,
337 338 339
	}
	CacheGCFlag = cli.IntFlag{
		Name:  "cache.gc",
340
		Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)",
341
		Value: 25,
342 343 344 345 346 347
	}
	TrieCacheGenFlag = cli.IntFlag{
		Name:  "trie-cache-gens",
		Usage: "Number of trie node generations to keep in memory",
		Value: int(state.MaxTrieCacheGen),
	}
348 349 350 351
	// Miner settings
	MiningEnabledFlag = cli.BoolFlag{
		Name:  "mine",
		Usage: "Enable mining",
352
	}
353
	MinerThreadsFlag = cli.IntFlag{
354
		Name:  "miner.threads",
355
		Usage: "Number of CPU threads to use for mining",
356 357
		Value: 0,
	}
358 359 360 361 362
	MinerLegacyThreadsFlag = cli.IntFlag{
		Name:  "minerthreads",
		Usage: "Number of CPU threads to use for mining (deprecated, use --miner.threads)",
		Value: 0,
	}
363 364 365
	MinerNotifyFlag = cli.StringFlag{
		Name:  "miner.notify",
		Usage: "Comma separated HTTP URL list to notify of new work packages",
366
	}
367 368 369
	MinerGasTargetFlag = cli.Uint64Flag{
		Name:  "miner.gastarget",
		Usage: "Target gas floor for mined blocks",
370
		Value: eth.DefaultConfig.MinerGasFloor,
371 372
	}
	MinerLegacyGasTargetFlag = cli.Uint64Flag{
373
		Name:  "targetgaslimit",
374
		Usage: "Target gas floor for mined blocks (deprecated, use --miner.gastarget)",
375 376 377 378 379 380
		Value: eth.DefaultConfig.MinerGasFloor,
	}
	MinerGasLimitFlag = cli.Uint64Flag{
		Name:  "miner.gaslimit",
		Usage: "Target gas ceiling for mined blocks",
		Value: eth.DefaultConfig.MinerGasCeil,
381
	}
382 383
	MinerGasPriceFlag = BigFlag{
		Name:  "miner.gasprice",
384
		Usage: "Minimum gas price for mining a transaction",
385
		Value: eth.DefaultConfig.MinerGasPrice,
Z
zelig 已提交
386
	}
387
	MinerLegacyGasPriceFlag = BigFlag{
388
		Name:  "gasprice",
389
		Usage: "Minimum gas price for mining a transaction (deprecated, use --miner.gasprice)",
390
		Value: eth.DefaultConfig.MinerGasPrice,
391
	}
392 393 394 395 396 397 398 399 400 401 402 403
	MinerEtherbaseFlag = cli.StringFlag{
		Name:  "miner.etherbase",
		Usage: "Public address for block mining rewards (default = first account)",
		Value: "0",
	}
	MinerLegacyEtherbaseFlag = cli.StringFlag{
		Name:  "etherbase",
		Usage: "Public address for block mining rewards (default = first account, deprecated, use --miner.etherbase)",
		Value: "0",
	}
	MinerExtraDataFlag = cli.StringFlag{
		Name:  "miner.extradata",
404
		Usage: "Block extra data set by the miner (default = client version)",
Z
zelig 已提交
405
	}
406 407 408 409
	MinerLegacyExtraDataFlag = cli.StringFlag{
		Name:  "extradata",
		Usage: "Block extra data set by the miner (default = client version, deprecated, use --miner.extradata)",
	}
410 411
	MinerRecommitIntervalFlag = cli.DurationFlag{
		Name:  "miner.recommit",
412
		Usage: "Time interval to recreate the block being mined",
413
		Value: eth.DefaultConfig.MinerRecommit,
414
	}
415 416 417 418
	MinerNoVerfiyFlag = cli.BoolFlag{
		Name:  "miner.noverify",
		Usage: "Disable remote sealing verification",
	}
419
	// Account settings
Z
zelig 已提交
420 421
	UnlockedAccountFlag = cli.StringFlag{
		Name:  "unlock",
422
		Usage: "Comma separated list of accounts to unlock",
Z
zelig 已提交
423 424 425 426
		Value: "",
	}
	PasswordFileFlag = cli.StringFlag{
		Name:  "password",
A
ayeowch 已提交
427
		Usage: "Password file to use for non-interactive password input",
Z
zelig 已提交
428
		Value: "",
Z
zelig 已提交
429
	}
430 431 432 433 434
	ExternalSignerFlag = cli.StringFlag{
		Name:  "signer",
		Usage: "External signer (url or path to ipc file)",
		Value: "",
	}
435 436 437 438
	VMEnableDebugFlag = cli.BoolFlag{
		Name:  "vmdebug",
		Usage: "Record information useful for VM and contract debugging",
	}
439 440 441 442 443
	// Logging and debug settings
	EthStatsURLFlag = cli.StringFlag{
		Name:  "ethstats",
		Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)",
	}
444 445 446 447
	FakePoWFlag = cli.BoolFlag{
		Name:  "fakepow",
		Usage: "Disables proof-of-work verification",
	}
448 449 450 451
	NoCompactionFlag = cli.BoolFlag{
		Name:  "nocompaction",
		Usage: "Disables db compaction after import",
	}
452 453 454
	// RPC settings
	RPCEnabledFlag = cli.BoolFlag{
		Name:  "rpc",
455
		Usage: "Enable the HTTP-RPC server",
456 457 458
	}
	RPCListenAddrFlag = cli.StringFlag{
		Name:  "rpcaddr",
459
		Usage: "HTTP-RPC server listening interface",
460
		Value: node.DefaultHTTPHost,
461 462 463
	}
	RPCPortFlag = cli.IntFlag{
		Name:  "rpcport",
464
		Usage: "HTTP-RPC server listening port",
465
		Value: node.DefaultHTTPPort,
466
	}
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
	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.rpccorsdomain",
		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
		Value: "",
	}
	GraphQLVirtualHostsFlag = cli.StringFlag{
		Name:  "graphql.rpcvhosts",
		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
		Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
	}
491 492
	RPCCORSDomainFlag = cli.StringFlag{
		Name:  "rpccorsdomain",
493
		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
494 495
		Value: "",
	}
496 497 498
	RPCVirtualHostsFlag = cli.StringFlag{
		Name:  "rpcvhosts",
		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
499
		Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
500
	}
501
	RPCApiFlag = cli.StringFlag{
502
		Name:  "rpcapi",
503
		Usage: "API's offered over the HTTP-RPC interface",
504
		Value: "",
505
	}
B
Bas van Kervel 已提交
506 507 508 509 510 511
	IPCDisabledFlag = cli.BoolFlag{
		Name:  "ipcdisable",
		Usage: "Disable the IPC-RPC server",
	}
	IPCPathFlag = DirectoryFlag{
		Name:  "ipcpath",
512
		Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)",
B
Bas van Kervel 已提交
513
	}
514
	WSEnabledFlag = cli.BoolFlag{
515
		Name:  "ws",
516 517 518 519 520
		Usage: "Enable the WS-RPC server",
	}
	WSListenAddrFlag = cli.StringFlag{
		Name:  "wsaddr",
		Usage: "WS-RPC server listening interface",
521
		Value: node.DefaultWSHost,
522 523 524 525
	}
	WSPortFlag = cli.IntFlag{
		Name:  "wsport",
		Usage: "WS-RPC server listening port",
526
		Value: node.DefaultWSPort,
527 528 529 530
	}
	WSApiFlag = cli.StringFlag{
		Name:  "wsapi",
		Usage: "API's offered over the WS-RPC interface",
531
		Value: "",
532
	}
B
Bas van Kervel 已提交
533 534 535
	WSAllowedOriginsFlag = cli.StringFlag{
		Name:  "wsorigins",
		Usage: "Origins from which to accept websockets requests",
536
		Value: "",
537
	}
538 539
	ExecFlag = cli.StringFlag{
		Name:  "exec",
540
		Usage: "Execute JavaScript statement",
541
	}
542
	PreloadJSFlag = cli.StringFlag{
543 544 545
		Name:  "preload",
		Usage: "Comma separated list of JavaScript files to preload into the console",
	}
546

547 548 549
	// Network Settings
	MaxPeersFlag = cli.IntFlag{
		Name:  "maxpeers",
550
		Usage: "Maximum number of network peers (network disabled if set to 0)",
551
		Value: 25,
552
	}
553 554 555 556 557
	MaxPendingPeersFlag = cli.IntFlag{
		Name:  "maxpendpeers",
		Usage: "Maximum number of pending connection attempts (defaults used if set to 0)",
		Value: 0,
	}
558 559 560 561 562
	ListenPortFlag = cli.IntFlag{
		Name:  "port",
		Usage: "Network listening port",
		Value: 30303,
	}
563
	BootnodesFlag = cli.StringFlag{
564
		Name:  "bootnodes",
565 566 567 568 569 570 571 572 573 574 575
		Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)",
		Value: "",
	}
	BootnodesV4Flag = cli.StringFlag{
		Name:  "bootnodesv4",
		Usage: "Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)",
		Value: "",
	}
	BootnodesV5Flag = cli.StringFlag{
		Name:  "bootnodesv5",
		Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)",
576
		Value: "",
577 578 579 580 581 582 583 584 585 586 587
	}
	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",
588
		Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
589 590
		Value: "any",
	}
591 592 593 594
	NoDiscoverFlag = cli.BoolFlag{
		Name:  "nodiscover",
		Usage: "Disables the peer discovery mechanism (manual peer addition)",
	}
595 596 597 598
	DiscoveryV5Flag = cli.BoolFlag{
		Name:  "v5disc",
		Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
	}
599 600 601 602 603
	NetrestrictFlag = cli.StringFlag{
		Name:  "netrestrict",
		Usage: "Restricts network communication to the given IP networks (CIDR masks)",
	}

604
	// ATM the url is left to the user and deployment to
Z
CLI:  
zelig 已提交
605 606
	JSpathFlag = cli.StringFlag{
		Name:  "jspath",
607
		Usage: "JavaScript root path for `loadScript`",
Z
CLI:  
zelig 已提交
608 609
		Value: ".",
	}
610 611

	// Gas price oracle settings
612 613 614
	GpoBlocksFlag = cli.IntFlag{
		Name:  "gpoblocks",
		Usage: "Number of recent blocks to check for gas prices",
615
		Value: eth.DefaultConfig.GPO.Blocks,
Z
zsfelfoldi 已提交
616
	}
617 618 619
	GpoPercentileFlag = cli.IntFlag{
		Name:  "gpopercentile",
		Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices",
620
		Value: eth.DefaultConfig.GPO.Percentile,
Z
zsfelfoldi 已提交
621
	}
622 623 624 625 626 627 628 629 630 631 632 633 634 635
	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,
	}
636 637 638 639
	WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{
		Name:  "shh.restrict-light",
		Usage: "Restrict connection between two whisper light clients",
	}
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669

	// Metrics flags
	MetricsEnabledFlag = cli.BoolFlag{
		Name:  metrics.MetricsEnabledFlag,
		Usage: "Enable metrics collection and reporting",
	}
	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",
	}
670 671 672
	// 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.
673
	// https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key
674 675 676 677
	MetricsInfluxDBTagsFlag = cli.StringFlag{
		Name:  "metrics.influxdb.tags",
		Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements",
		Value: "host=localhost",
678
	}
679 680 681 682 683 684 685 686 687 688 689

	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: "",
	}
690 691
)

692
// MakeDataDir retrieves the currently requested data directory, terminating
693 694
// if none (or the empty string) is specified. If the node is starting a testnet,
// the a subdirectory of the specified datadir will be used.
695
func MakeDataDir(ctx *cli.Context) string {
696
	if path := ctx.GlobalString(DataDirFlag.Name); path != "" {
697
		if ctx.GlobalBool(TestnetFlag.Name) {
698
			return filepath.Join(path, "testnet")
699
		}
700 701 702
		if ctx.GlobalBool(RinkebyFlag.Name) {
			return filepath.Join(path, "rinkeby")
		}
703 704 705
		if ctx.GlobalBool(GoerliFlag.Name) {
			return filepath.Join(path, "goerli")
		}
706
		return path
707
	}
708
	Fatalf("Cannot determine default data directory, please set manually (--datadir)")
709
	return ""
710 711
}

712
// setNodeKey creates a node key from set command line flags, either loading it
713 714
// 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.
715
func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
716 717 718
	var (
		hex  = ctx.GlobalString(NodeKeyHexFlag.Name)
		file = ctx.GlobalString(NodeKeyFileFlag.Name)
719 720
		key  *ecdsa.PrivateKey
		err  error
721
	)
722 723
	switch {
	case file != "" && hex != "":
724
		Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name)
725 726
	case file != "":
		if key, err = crypto.LoadECDSA(file); err != nil {
727
			Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err)
728
		}
729
		cfg.PrivateKey = key
730 731
	case hex != "":
		if key, err = crypto.HexToECDSA(hex); err != nil {
732
			Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err)
733
		}
734
		cfg.PrivateKey = key
735 736 737
	}
}

738 739
// setNodeUserIdent creates the user identifier from CLI flags.
func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
740
	if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 {
741
		cfg.UserIdent = identity
742 743 744
	}
}

745
// setBootstrapNodes creates a list of bootstrap nodes from the command line
746
// flags, reverting to pre-configured ones if none have been specified.
747
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
748
	urls := params.MainnetBootnodes
749
	switch {
750 751 752 753 754 755
	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name):
		if ctx.GlobalIsSet(BootnodesV4Flag.Name) {
			urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",")
		} else {
			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
		}
756
	case ctx.GlobalBool(TestnetFlag.Name):
757
		urls = params.TestnetBootnodes
758 759
	case ctx.GlobalBool(RinkebyFlag.Name):
		urls = params.RinkebyBootnodes
760 761
	case ctx.GlobalBool(GoerliFlag.Name):
		urls = params.GoerliBootnodes
762 763
	case cfg.BootstrapNodes != nil:
		return // already set, don't apply defaults.
764 765
	}

766
	cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls))
767
	for _, url := range urls {
768 769 770 771 772 773
		if url != "" {
			node, err := enode.ParseV4(url)
			if err != nil {
				log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
			}
			cfg.BootstrapNodes = append(cfg.BootstrapNodes, node)
774 775 776 777
		}
	}
}

778
// setBootstrapNodesV5 creates a list of bootstrap nodes from the command line
779
// flags, reverting to pre-configured ones if none have been specified.
780
func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
781
	urls := params.DiscoveryV5Bootnodes
782
	switch {
783 784 785 786 787 788
	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name):
		if ctx.GlobalIsSet(BootnodesV5Flag.Name) {
			urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",")
		} else {
			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
		}
789
	case ctx.GlobalBool(RinkebyFlag.Name):
790
		urls = params.RinkebyBootnodes
791 792
	case ctx.GlobalBool(GoerliFlag.Name):
		urls = params.GoerliBootnodes
793
	case cfg.BootstrapNodesV5 != nil:
794
		return // already set, don't apply defaults.
795 796
	}

797
	cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls))
798
	for _, url := range urls {
799 800
		node, err := discv5.ParseNode(url)
		if err != nil {
P
Péter Szilágyi 已提交
801
			log.Error("Bootstrap URL invalid", "enode", url, "err", err)
802 803
			continue
		}
804
		cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node)
805 806 807
	}
}

808
// setListenAddress creates a TCP listening address string from set command
809
// line flags.
810 811 812 813
func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
	if ctx.GlobalIsSet(ListenPortFlag.Name) {
		cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
	}
814 815
}

816 817 818 819 820 821 822 823
// 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
824 825 826
	}
}

827 828 829
// splitAndTrim splits input separated by a comma
// and trims excessive white space from the substrings.
func splitAndTrim(input string) []string {
830 831 832 833 834 835 836
	result := strings.Split(input, ",")
	for i, r := range result {
		result[i] = strings.TrimSpace(r)
	}
	return result
}

837
// setHTTP creates the HTTP RPC listener interface string from the set
838
// command line flags, returning empty if the HTTP endpoint is disabled.
839 840 841 842 843 844 845 846 847 848 849 850
func setHTTP(ctx *cli.Context, cfg *node.Config) {
	if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" {
		cfg.HTTPHost = "127.0.0.1"
		if ctx.GlobalIsSet(RPCListenAddrFlag.Name) {
			cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name)
		}
	}

	if ctx.GlobalIsSet(RPCPortFlag.Name) {
		cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name)
	}
	if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) {
851
		cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name))
852 853
	}
	if ctx.GlobalIsSet(RPCApiFlag.Name) {
854
		cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
855
	}
856 857 858
	if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) {
		cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
	}
859 860
}

861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
// 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))
	}
}

879
// setWS creates the WebSocket RPC listener interface string from the set
880
// command line flags, returning empty if the HTTP endpoint is disabled.
881 882 883 884 885 886 887 888 889 890 891 892
func setWS(ctx *cli.Context, cfg *node.Config) {
	if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" {
		cfg.WSHost = "127.0.0.1"
		if ctx.GlobalIsSet(WSListenAddrFlag.Name) {
			cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name)
		}
	}

	if ctx.GlobalIsSet(WSPortFlag.Name) {
		cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name)
	}
	if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) {
893
		cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name))
894 895
	}
	if ctx.GlobalIsSet(WSApiFlag.Name) {
896
		cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name))
897 898 899 900 901 902 903 904 905 906 907 908
	}
}

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

912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
// SetULC setup ULC config from file if given.
func SetULC(ctx *cli.Context, cfg *eth.Config) {
	// ULC config isn't loaded from global config and ULC config and ULC trusted nodes are not defined.
	if cfg.ULC == nil && !(ctx.GlobalIsSet(ULCModeConfigFlag.Name) || ctx.GlobalIsSet(ULCTrustedNodesFlag.Name)) {
		return
	}
	cfg.ULC = &eth.ULCConfig{}

	path := ctx.GlobalString(ULCModeConfigFlag.Name)
	if path != "" {
		cfgData, err := ioutil.ReadFile(path)
		if err != nil {
			Fatalf("Failed to unmarshal ULC configuration: %v", err)
		}

		err = json.Unmarshal(cfgData, &cfg.ULC)
		if err != nil {
			Fatalf("Failed to unmarshal ULC configuration: %s", err.Error())
		}
	}

	if trustedNodes := ctx.GlobalString(ULCTrustedNodesFlag.Name); trustedNodes != "" {
		cfg.ULC.TrustedServers = strings.Split(trustedNodes, ",")
	}

	if trustedFraction := ctx.GlobalInt(ULCMinTrustedFractionFlag.Name); trustedFraction > 0 {
		cfg.ULC.MinTrustedFraction = trustedFraction
	}
	if cfg.ULC.MinTrustedFraction <= 0 && cfg.ULC.MinTrustedFraction > 100 {
		log.Error("MinTrustedFraction is invalid", "MinTrustedFraction", cfg.ULC.MinTrustedFraction, "Changed to default", eth.DefaultULCMinTrustedFraction)
		cfg.ULC.MinTrustedFraction = eth.DefaultULCMinTrustedFraction
	}
}

946
// makeDatabaseHandles raises out the number of allowed file handles per process
947
// for Geth and returns half of the allowance to assign to the database.
948
func makeDatabaseHandles() int {
949
	limit, err := fdlimit.Maximum()
950
	if err != nil {
951
		Fatalf("Failed to retrieve file descriptor allowance: %v", err)
952
	}
953 954
	raised, err := fdlimit.Raise(uint64(limit))
	if err != nil {
955
		Fatalf("Failed to raise file descriptor allowance: %v", err)
956
	}
957
	return int(raised / 2) // Leave half for networking and other stuff
958 959
}

960 961
// MakeAddress converts an account specified directly as a hex encoded string or
// a key index in the key store to an internal account representation.
962
func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
963 964
	// If the specified account is a valid address, return it
	if common.IsHexAddress(account) {
F
Felix Lange 已提交
965
		return accounts.Account{Address: common.HexToAddress(account)}, nil
966 967 968
	}
	// Otherwise try to interpret the account as a keystore index
	index, err := strconv.Atoi(account)
969
	if err != nil || index < 0 {
F
Felix Lange 已提交
970
		return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account)
971
	}
972 973 974 975 976 977
	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("-------------------------------------------------------------------")

978 979 980 981 982
	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
983 984
}

985
// setEtherbase retrieves the etherbase either from the directly specified
986
// command line flags or from the keystore if CLI indexed.
987
func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) {
988 989 990 991 992 993 994 995 996 997
	// Extract the current etherbase, new flag overriding legacy one
	var etherbase string
	if ctx.GlobalIsSet(MinerLegacyEtherbaseFlag.Name) {
		etherbase = ctx.GlobalString(MinerLegacyEtherbaseFlag.Name)
	}
	if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) {
		etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name)
	}
	// Convert the etherbase into an address and configure it
	if etherbase != "" {
998 999 1000 1001 1002 1003 1004 1005
		if ks != nil {
			account, err := MakeAddress(ks, etherbase)
			if err != nil {
				Fatalf("Invalid miner etherbase: %v", err)
			}
			cfg.Etherbase = account.Address
		} else {
			Fatalf("No etherbase configured")
1006
		}
1007
	}
1008 1009
}

1010
// MakePasswordList reads password lines from the file specified by the global --password flag.
1011
func MakePasswordList(ctx *cli.Context) []string {
1012 1013 1014 1015 1016 1017
	path := ctx.GlobalString(PasswordFileFlag.Name)
	if path == "" {
		return nil
	}
	text, err := ioutil.ReadFile(path)
	if err != nil {
1018
		Fatalf("Failed to read password file: %v", err)
1019 1020 1021 1022 1023
	}
	lines := strings.Split(string(text), "\n")
	// Sanitise DOS line endings.
	for i := range lines {
		lines[i] = strings.TrimRight(lines[i], "\r")
1024
	}
1025
	return lines
1026 1027
}

1028 1029 1030 1031 1032 1033 1034
func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
	setNodeKey(ctx, cfg)
	setNAT(ctx, cfg)
	setListenAddress(ctx, cfg)
	setBootstrapNodes(ctx, cfg)
	setBootstrapNodesV5(ctx, cfg)

1035
	lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light"
1036 1037 1038
	lightServer := ctx.GlobalInt(LightServFlag.Name) != 0
	lightPeers := ctx.GlobalInt(LightPeersFlag.Name)

1039 1040
	if ctx.GlobalIsSet(MaxPeersFlag.Name) {
		cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
1041 1042 1043
		if lightServer && !ctx.GlobalIsSet(LightPeersFlag.Name) {
			cfg.MaxPeers += lightPeers
		}
1044 1045 1046 1047 1048 1049 1050
	} else {
		if lightServer {
			cfg.MaxPeers += lightPeers
		}
		if lightClient && ctx.GlobalIsSet(LightPeersFlag.Name) && cfg.MaxPeers < lightPeers {
			cfg.MaxPeers = lightPeers
		}
1051
	}
1052 1053 1054 1055 1056 1057 1058 1059 1060
	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)

1061 1062 1063
	if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) {
		cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name)
	}
1064
	if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient {
1065
		cfg.NoDiscovery = true
1066 1067
	}

1068 1069 1070
	// 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
1071
	forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name)
1072 1073 1074 1075
	if ctx.GlobalIsSet(DiscoveryV5Flag.Name) {
		cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name)
	} else if forceV5Discovery {
		cfg.DiscoveryV5 = true
1076
	}
1077

1078 1079 1080
	if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" {
		list, err := netutil.ParseNetlist(netrestrict)
		if err != nil {
1081
			Fatalf("Option %q: %v", NetrestrictFlag.Name, err)
1082
		}
1083
		cfg.NetRestrict = list
1084 1085
	}

1086
	if ctx.GlobalBool(DeveloperFlag.Name) {
1087 1088 1089 1090 1091
		// --dev mode can't use p2p networking.
		cfg.MaxPeers = 0
		cfg.ListenAddr = ":0"
		cfg.NoDiscovery = true
		cfg.DiscoveryV5 = false
1092 1093 1094
	}
}

1095 1096 1097 1098 1099
// 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)
1100
	setGraphQL(ctx, cfg)
1101 1102
	setWS(ctx, cfg)
	setNodeUserIdent(ctx, cfg)
1103
	setDataDir(ctx, cfg)
1104

1105 1106 1107 1108
	if ctx.GlobalIsSet(ExternalSignerFlag.Name) {
		cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name)
	}

1109 1110 1111 1112 1113 1114
	if ctx.GlobalIsSet(KeyStoreDirFlag.Name) {
		cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name)
	}
	if ctx.GlobalIsSet(LightKDFFlag.Name) {
		cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name)
	}
1115 1116 1117
	if ctx.GlobalIsSet(NoUSBFlag.Name) {
		cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name)
	}
1118 1119
}

1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
func setDataDir(ctx *cli.Context, cfg *node.Config) {
	switch {
	case ctx.GlobalIsSet(DataDirFlag.Name):
		cfg.DataDir = ctx.GlobalString(DataDirFlag.Name)
	case ctx.GlobalBool(DeveloperFlag.Name):
		cfg.DataDir = "" // unless explicitly requested, use memory databases
	case ctx.GlobalBool(TestnetFlag.Name):
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet")
	case ctx.GlobalBool(RinkebyFlag.Name):
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
1130 1131
	case ctx.GlobalBool(GoerliFlag.Name):
		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
1132 1133 1134
	}
}

1135 1136 1137 1138 1139 1140 1141 1142 1143
func setGPO(ctx *cli.Context, cfg *gasprice.Config) {
	if ctx.GlobalIsSet(GpoBlocksFlag.Name) {
		cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name)
	}
	if ctx.GlobalIsSet(GpoPercentileFlag.Name) {
		cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name)
	}
}

1144
func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) {
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
	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))
			}
		}
	}
1155 1156 1157
	if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) {
		cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name)
	}
1158 1159 1160 1161 1162 1163
	if ctx.GlobalIsSet(TxPoolJournalFlag.Name) {
		cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name)
	}
	if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) {
		cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name)
	}
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
	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)
	}
}

1187 1188
func setEthash(ctx *cli.Context, cfg *eth.Config) {
	if ctx.GlobalIsSet(EthashCacheDirFlag.Name) {
1189
		cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name)
1190 1191
	}
	if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) {
1192
		cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name)
1193 1194
	}
	if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) {
1195
		cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name)
1196 1197
	}
	if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) {
1198
		cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name)
1199 1200
	}
	if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) {
1201
		cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name)
1202 1203
	}
	if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) {
1204
		cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name)
1205 1206 1207
	}
}

1208
func setWhitelist(ctx *cli.Context, cfg *eth.Config) {
1209 1210 1211 1212 1213 1214 1215 1216 1217
	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)
1218
		}
1219 1220 1221 1222 1223 1224 1225 1226 1227
		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
1228 1229 1230
	}
}

1231
// checkExclusive verifies that only a single instance of the provided flags was
1232 1233 1234
// set by the user. Each flag might optionally be followed by a string type to
// specialize it further.
func checkExclusive(ctx *cli.Context, args ...interface{}) {
1235
	set := make([]string, 0, 1)
1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
	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:
1248
				// Extended flag check, make sure value set doesn't conflict with passed in option
1249 1250
				if ctx.GlobalString(flag.GetName()) == option {
					name += "=" + option
1251
					set = append(set, "--"+name)
1252
				}
1253
				// shift arguments and continue
1254
				i++
1255
				continue
1256 1257 1258 1259 1260 1261 1262

			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
1263
		if ctx.GlobalIsSet(flag.GetName()) {
1264
			set = append(set, "--"+name)
1265 1266
		}
	}
1267
	if len(set) > 1 {
1268
		Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", "))
1269
	}
1270 1271
}

1272 1273
// SetShhConfig applies shh-related command line flags to the config.
func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
1274 1275
	if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) {
		cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name))
1276
	}
1277 1278
	if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) {
		cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name)
1279
	}
1280 1281 1282
	if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) {
		cfg.RestrictConnectionBetweenLightClients = true
	}
1283 1284
}

1285 1286 1287
// 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
1288
	checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag, GoerliFlag)
1289
	checkExclusive(ctx, LightServFlag, SyncModeFlag, "light")
1290 1291 1292 1293 1294 1295
	// Can't use both ephemeral unlocked and external signer
	checkExclusive(ctx, DeveloperFlag, ExternalSignerFlag)
	var ks *keystore.KeyStore
	if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 {
		ks = keystores[0].(*keystore.KeyStore)
	}
1296 1297
	setEtherbase(ctx, ks, cfg)
	setGPO(ctx, &cfg.GPO)
1298
	setTxPool(ctx, &cfg.TxPool)
1299
	setEthash(ctx, cfg)
1300
	setWhitelist(ctx, cfg)
1301

1302
	if ctx.GlobalIsSet(SyncModeFlag.Name) {
1303 1304 1305 1306 1307 1308 1309 1310
		cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)
	}
	if ctx.GlobalIsSet(LightServFlag.Name) {
		cfg.LightServ = ctx.GlobalInt(LightServFlag.Name)
	}
	if ctx.GlobalIsSet(LightPeersFlag.Name) {
		cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name)
	}
1311 1312 1313
	if ctx.GlobalIsSet(OnlyAnnounceModeFlag.Name) {
		cfg.OnlyAnnounce = ctx.GlobalBool(OnlyAnnounceModeFlag.Name)
	}
1314
	if ctx.GlobalIsSet(NetworkIdFlag.Name) {
1315
		cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name)
1316
	}
1317 1318
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) {
		cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
1319 1320 1321
	}
	cfg.DatabaseHandles = makeDatabaseHandles()

1322 1323 1324 1325 1326
	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
	}
	cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"

1327 1328 1329
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
		cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
	}
1330
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
1331
		cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
1332
	}
1333 1334 1335
	if ctx.GlobalIsSet(MinerNotifyFlag.Name) {
		cfg.MinerNotify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",")
	}
1336 1337 1338
	if ctx.GlobalIsSet(DocRootFlag.Name) {
		cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name)
	}
1339
	if ctx.GlobalIsSet(MinerLegacyExtraDataFlag.Name) {
1340
		cfg.MinerExtraData = []byte(ctx.GlobalString(MinerLegacyExtraDataFlag.Name))
1341
	}
1342
	if ctx.GlobalIsSet(MinerExtraDataFlag.Name) {
1343
		cfg.MinerExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name))
1344
	}
1345 1346 1347 1348 1349 1350 1351 1352 1353
	if ctx.GlobalIsSet(MinerLegacyGasTargetFlag.Name) {
		cfg.MinerGasFloor = ctx.GlobalUint64(MinerLegacyGasTargetFlag.Name)
	}
	if ctx.GlobalIsSet(MinerGasTargetFlag.Name) {
		cfg.MinerGasFloor = ctx.GlobalUint64(MinerGasTargetFlag.Name)
	}
	if ctx.GlobalIsSet(MinerGasLimitFlag.Name) {
		cfg.MinerGasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name)
	}
1354
	if ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
1355
		cfg.MinerGasPrice = GlobalBig(ctx, MinerLegacyGasPriceFlag.Name)
1356 1357
	}
	if ctx.GlobalIsSet(MinerGasPriceFlag.Name) {
1358 1359 1360 1361
		cfg.MinerGasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name)
	}
	if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) {
		cfg.MinerRecommit = ctx.Duration(MinerRecommitIntervalFlag.Name)
1362
	}
1363 1364 1365
	if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) {
		cfg.MinerNoverify = ctx.Bool(MinerNoVerfiyFlag.Name)
	}
1366 1367 1368 1369
	if ctx.GlobalIsSet(VMEnableDebugFlag.Name) {
		// TODO(fjl): force-enable this in --dev mode
		cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
	}
1370

1371 1372 1373 1374 1375 1376 1377 1378
	if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) {
		cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name)
	}

	if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
		cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
	}

1379
	// Override any default configs for hard coded networks.
1380
	switch {
1381
	case ctx.GlobalBool(TestnetFlag.Name):
1382
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
1383
			cfg.NetworkId = 3
1384
		}
1385
		cfg.Genesis = core.DefaultTestnetGenesisBlock()
1386 1387 1388 1389 1390
	case ctx.GlobalBool(RinkebyFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 4
		}
		cfg.Genesis = core.DefaultRinkebyGenesisBlock()
1391 1392 1393 1394 1395
	case ctx.GlobalBool(GoerliFlag.Name):
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 5
		}
		cfg.Genesis = core.DefaultGoerliGenesisBlock()
1396
	case ctx.GlobalBool(DeveloperFlag.Name):
1397 1398 1399
		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
			cfg.NetworkId = 1337
		}
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418
		// 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)
1419
		if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
1420
			cfg.MinerGasPrice = big.NewInt(1)
1421 1422
		}
	}
1423
	// TODO(fjl): move trie cache generations into config
1424 1425 1426
	if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 {
		state.MaxTrieCacheGen = uint16(gen)
	}
1427
}
1428

1429 1430 1431 1432 1433 1434 1435
// SetDashboardConfig applies dashboard related command line flags to the config.
func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
	cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
	cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
	cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
}

1436 1437 1438 1439 1440 1441 1442
// 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)
		})
1443
	} else {
1444 1445 1446 1447
		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)
1448 1449 1450
				fullNode.AddLesServer(ls)
			}
			return fullNode, err
1451 1452 1453 1454
		})
	}
	if err != nil {
		Fatalf("Failed to register the Ethereum service: %v", err)
1455
	}
1456 1457
}

1458
// RegisterDashboardService adds a dashboard to the stack.
1459
func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) {
1460
	stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
1461
		return dashboard.New(cfg, commit, ctx.ResolvePath("logs")), nil
1462 1463 1464
	})
}

1465
// RegisterShhService configures Whisper and adds it to the given node.
1466 1467 1468 1469
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 {
1470
		Fatalf("Failed to register the Whisper service: %v", err)
1471
	}
1472 1473
}

1474
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
S
Sarlor 已提交
1475
// the given node.
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
func RegisterEthStatsService(stack *node.Node, url string) {
	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
		// Retrieve both eth and les services
		var ethServ *eth.Ethereum
		ctx.Service(&ethServ)

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

		return ethstats.New(url, ethServ, lesServ)
	}); err != nil {
1487
		Fatalf("Failed to register the Ethereum Stats service: %v", err)
1488 1489 1490
	}
}

1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502
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 {
1503 1504
			tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name))

1505
			log.Info("Enabling metrics export to InfluxDB")
1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522

			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]
			}
1523 1524
		}
	}
1525 1526

	return tagsMap
1527 1528
}

1529
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
1530
func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
1531
	var (
1532
		cache   = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
1533
		handles = makeDatabaseHandles()
1534
	)
1535
	name := "chaindata"
1536
	if ctx.GlobalString(SyncModeFlag.Name) == "light" {
1537 1538
		name = "lightchaindata"
	}
1539
	chainDb, err := stack.OpenDatabase(name, cache, handles)
1540
	if err != nil {
1541
		Fatalf("Could not open database: %v", err)
1542
	}
1543 1544 1545
	return chainDb
}

F
Felix Lange 已提交
1546 1547 1548
func MakeGenesis(ctx *cli.Context) *core.Genesis {
	var genesis *core.Genesis
	switch {
1549
	case ctx.GlobalBool(TestnetFlag.Name):
F
Felix Lange 已提交
1550
		genesis = core.DefaultTestnetGenesisBlock()
1551 1552
	case ctx.GlobalBool(RinkebyFlag.Name):
		genesis = core.DefaultRinkebyGenesisBlock()
1553 1554
	case ctx.GlobalBool(GoerliFlag.Name):
		genesis = core.DefaultGoerliGenesisBlock()
1555 1556
	case ctx.GlobalBool(DeveloperFlag.Name):
		Fatalf("Developer chains are ephemeral")
F
Felix Lange 已提交
1557 1558 1559 1560
	}
	return genesis
}

1561
// MakeChain creates a chain manager from set command line flags.
1562
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
1563
	var err error
1564
	chainDb = MakeChainDatabase(ctx, stack)
F
Felix Lange 已提交
1565 1566 1567 1568
	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
	if err != nil {
		Fatalf("%v", err)
	}
1569 1570 1571 1572 1573 1574
	var engine consensus.Engine
	if config.Clique != nil {
		engine = clique.New(config.Clique, chainDb)
	} else {
		engine = ethash.NewFaker()
		if !ctx.GlobalBool(FakePoWFlag.Name) {
1575 1576 1577 1578 1579 1580 1581
			engine = ethash.New(ethash.Config{
				CacheDir:       stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir),
				CachesInMem:    eth.DefaultConfig.Ethash.CachesInMem,
				CachesOnDisk:   eth.DefaultConfig.Ethash.CachesOnDisk,
				DatasetDir:     stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir),
				DatasetsInMem:  eth.DefaultConfig.Ethash.DatasetsInMem,
				DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk,
1582
			}, nil, false)
1583 1584
		}
	}
1585 1586 1587 1588
	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
	}
	cache := &core.CacheConfig{
1589 1590 1591 1592 1593 1594 1595
		Disabled:       ctx.GlobalString(GCModeFlag.Name) == "archive",
		TrieCleanLimit: eth.DefaultConfig.TrieCleanCache,
		TrieDirtyLimit: eth.DefaultConfig.TrieDirtyCache,
		TrieTimeLimit:  eth.DefaultConfig.TrieTimeout,
	}
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
		cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
1596 1597
	}
	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
1598
		cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
1599
	}
F
Felix Lange 已提交
1600
	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
1601
	chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil)
O
obscuren 已提交
1602
	if err != nil {
F
Felix Lange 已提交
1603
		Fatalf("Can't create BlockChain: %v", err)
O
obscuren 已提交
1604
	}
1605
	return chain, chainDb
1606
}
1607 1608 1609 1610 1611 1612 1613 1614 1615

// 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
1616
	var preloads []string
1617 1618 1619 1620 1621 1622 1623

	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
}
1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647

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