github.com/luckypickle/go-ethereum-vet@v1.14.2/cmd/utils/flags.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // 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/>. 16 17 // Package utils contains internal helper functions for go-ethereum commands. 18 package utils 19 20 import ( 21 "crypto/ecdsa" 22 "fmt" 23 "io/ioutil" 24 "math/big" 25 "os" 26 "path/filepath" 27 "strconv" 28 "strings" 29 "time" 30 31 "github.com/luckypickle/go-ethereum-vet/accounts" 32 "github.com/luckypickle/go-ethereum-vet/accounts/keystore" 33 "github.com/luckypickle/go-ethereum-vet/common" 34 "github.com/luckypickle/go-ethereum-vet/common/fdlimit" 35 "github.com/luckypickle/go-ethereum-vet/consensus" 36 "github.com/luckypickle/go-ethereum-vet/consensus/clique" 37 "github.com/luckypickle/go-ethereum-vet/consensus/ethash" 38 "github.com/luckypickle/go-ethereum-vet/core" 39 "github.com/luckypickle/go-ethereum-vet/core/state" 40 "github.com/luckypickle/go-ethereum-vet/core/vm" 41 "github.com/luckypickle/go-ethereum-vet/crypto" 42 "github.com/luckypickle/go-ethereum-vet/eth" 43 "github.com/luckypickle/go-ethereum-vet/eth/downloader" 44 "github.com/luckypickle/go-ethereum-vet/eth/gasprice" 45 "github.com/luckypickle/go-ethereum-vet/ethdb" 46 "github.com/luckypickle/go-ethereum-vet/ethstats" 47 "github.com/luckypickle/go-ethereum-vet/les" 48 "github.com/luckypickle/go-ethereum-vet/log" 49 "github.com/luckypickle/go-ethereum-vet/metrics" 50 "github.com/luckypickle/go-ethereum-vet/metrics/influxdb" 51 "github.com/luckypickle/go-ethereum-vet/node" 52 "github.com/luckypickle/go-ethereum-vet/p2p" 53 "github.com/luckypickle/go-ethereum-vet/p2p/discover" 54 "github.com/luckypickle/go-ethereum-vet/p2p/discv5" 55 "github.com/luckypickle/go-ethereum-vet/p2p/nat" 56 "github.com/luckypickle/go-ethereum-vet/p2p/netutil" 57 "github.com/luckypickle/go-ethereum-vet/params" 58 whisper "github.com/luckypickle/go-ethereum-vet/whisper/whisperv6" 59 "gopkg.in/urfave/cli.v1" 60 ) 61 62 var ( 63 CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} [arguments...] 64 {{if .cmd.Description}}{{.cmd.Description}} 65 {{end}}{{if .cmd.Subcommands}} 66 SUBCOMMANDS: 67 {{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} 68 {{end}}{{end}}{{if .categorizedFlags}} 69 {{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS: 70 {{range $categorized.Flags}}{{"\t"}}{{.}} 71 {{end}} 72 {{end}}{{end}}` 73 ) 74 75 func init() { 76 cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] 77 78 VERSION: 79 {{.Version}} 80 81 COMMANDS: 82 {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} 83 {{end}}{{if .Flags}} 84 GLOBAL OPTIONS: 85 {{range .Flags}}{{.}} 86 {{end}}{{end}} 87 ` 88 89 cli.CommandHelpTemplate = CommandHelpTemplate 90 } 91 92 // NewApp creates an app with sane defaults. 93 func NewApp(gitCommit, usage string) *cli.App { 94 app := cli.NewApp() 95 app.Name = filepath.Base(os.Args[0]) 96 app.Author = "" 97 //app.Authors = nil 98 app.Email = "" 99 app.Version = params.VersionWithMeta 100 if len(gitCommit) >= 8 { 101 app.Version += "-" + gitCommit[:8] 102 } 103 app.Usage = usage 104 return app 105 } 106 107 // These are all the command line flags we support. 108 // If you add to this list, please remember to include the 109 // flag in the appropriate command definition. 110 // 111 // The flags are defined here so their names and help texts 112 // are the same for all commands. 113 114 var ( 115 // General settings 116 DataDirFlag = DirectoryFlag{ 117 Name: "datadir", 118 Usage: "Data directory for the databases and keystore", 119 Value: DirectoryString{node.DefaultDataDir()}, 120 } 121 KeyStoreDirFlag = DirectoryFlag{ 122 Name: "keystore", 123 Usage: "Directory for the keystore (default = inside the datadir)", 124 } 125 NoUSBFlag = cli.BoolFlag{ 126 Name: "nousb", 127 Usage: "Disables monitoring for and managing USB hardware wallets", 128 } 129 NetworkIdFlag = cli.Uint64Flag{ 130 Name: "networkid", 131 Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)", 132 Value: eth.DefaultConfig.NetworkId, 133 } 134 TestnetFlag = cli.BoolFlag{ 135 Name: "testnet", 136 Usage: "Ropsten network: pre-configured proof-of-work test network", 137 } 138 RinkebyFlag = cli.BoolFlag{ 139 Name: "rinkeby", 140 Usage: "Rinkeby network: pre-configured proof-of-authority test network", 141 } 142 DeveloperFlag = cli.BoolFlag{ 143 Name: "dev", 144 Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled", 145 } 146 DeveloperPeriodFlag = cli.IntFlag{ 147 Name: "dev.period", 148 Usage: "Block period to use in developer mode (0 = mine only if transaction pending)", 149 } 150 IdentityFlag = cli.StringFlag{ 151 Name: "identity", 152 Usage: "Custom node name", 153 } 154 DocRootFlag = DirectoryFlag{ 155 Name: "docroot", 156 Usage: "Document Root for HTTPClient file scheme", 157 Value: DirectoryString{homeDir()}, 158 } 159 defaultSyncMode = eth.DefaultConfig.SyncMode 160 SyncModeFlag = TextMarshalerFlag{ 161 Name: "syncmode", 162 Usage: `Blockchain sync mode ("fast", "full", or "light")`, 163 Value: &defaultSyncMode, 164 } 165 GCModeFlag = cli.StringFlag{ 166 Name: "gcmode", 167 Usage: `Blockchain garbage collection mode ("full", "archive")`, 168 Value: "full", 169 } 170 LightServFlag = cli.IntFlag{ 171 Name: "lightserv", 172 Usage: "Maximum percentage of time allowed for serving LES requests (0-90)", 173 Value: 0, 174 } 175 LightPeersFlag = cli.IntFlag{ 176 Name: "lightpeers", 177 Usage: "Maximum number of LES client peers", 178 Value: eth.DefaultConfig.LightPeers, 179 } 180 LightKDFFlag = cli.BoolFlag{ 181 Name: "lightkdf", 182 Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", 183 } 184 // Ethash settings 185 EthashCacheDirFlag = DirectoryFlag{ 186 Name: "ethash.cachedir", 187 Usage: "Directory to store the ethash verification caches (default = inside the datadir)", 188 } 189 EthashCachesInMemoryFlag = cli.IntFlag{ 190 Name: "ethash.cachesinmem", 191 Usage: "Number of recent ethash caches to keep in memory (16MB each)", 192 Value: eth.DefaultConfig.Ethash.CachesInMem, 193 } 194 EthashCachesOnDiskFlag = cli.IntFlag{ 195 Name: "ethash.cachesondisk", 196 Usage: "Number of recent ethash caches to keep on disk (16MB each)", 197 Value: eth.DefaultConfig.Ethash.CachesOnDisk, 198 } 199 EthashDatasetDirFlag = DirectoryFlag{ 200 Name: "ethash.dagdir", 201 Usage: "Directory to store the ethash mining DAGs (default = inside home folder)", 202 Value: DirectoryString{eth.DefaultConfig.Ethash.DatasetDir}, 203 } 204 EthashDatasetsInMemoryFlag = cli.IntFlag{ 205 Name: "ethash.dagsinmem", 206 Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)", 207 Value: eth.DefaultConfig.Ethash.DatasetsInMem, 208 } 209 EthashDatasetsOnDiskFlag = cli.IntFlag{ 210 Name: "ethash.dagsondisk", 211 Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)", 212 Value: eth.DefaultConfig.Ethash.DatasetsOnDisk, 213 } 214 // Transaction pool settings 215 TxPoolLocalsFlag = cli.StringFlag{ 216 Name: "txpool.locals", 217 Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)", 218 } 219 TxPoolNoLocalsFlag = cli.BoolFlag{ 220 Name: "txpool.nolocals", 221 Usage: "Disables price exemptions for locally submitted transactions", 222 } 223 TxPoolJournalFlag = cli.StringFlag{ 224 Name: "txpool.journal", 225 Usage: "Disk journal for local transaction to survive node restarts", 226 Value: core.DefaultTxPoolConfig.Journal, 227 } 228 TxPoolRejournalFlag = cli.DurationFlag{ 229 Name: "txpool.rejournal", 230 Usage: "Time interval to regenerate the local transaction journal", 231 Value: core.DefaultTxPoolConfig.Rejournal, 232 } 233 TxPoolPriceLimitFlag = cli.Uint64Flag{ 234 Name: "txpool.pricelimit", 235 Usage: "Minimum gas price limit to enforce for acceptance into the pool", 236 Value: eth.DefaultConfig.TxPool.PriceLimit, 237 } 238 TxPoolPriceBumpFlag = cli.Uint64Flag{ 239 Name: "txpool.pricebump", 240 Usage: "Price bump percentage to replace an already existing transaction", 241 Value: eth.DefaultConfig.TxPool.PriceBump, 242 } 243 TxPoolAccountSlotsFlag = cli.Uint64Flag{ 244 Name: "txpool.accountslots", 245 Usage: "Minimum number of executable transaction slots guaranteed per account", 246 Value: eth.DefaultConfig.TxPool.AccountSlots, 247 } 248 TxPoolGlobalSlotsFlag = cli.Uint64Flag{ 249 Name: "txpool.globalslots", 250 Usage: "Maximum number of executable transaction slots for all accounts", 251 Value: eth.DefaultConfig.TxPool.GlobalSlots, 252 } 253 TxPoolAccountQueueFlag = cli.Uint64Flag{ 254 Name: "txpool.accountqueue", 255 Usage: "Maximum number of non-executable transaction slots permitted per account", 256 Value: eth.DefaultConfig.TxPool.AccountQueue, 257 } 258 TxPoolGlobalQueueFlag = cli.Uint64Flag{ 259 Name: "txpool.globalqueue", 260 Usage: "Maximum number of non-executable transaction slots for all accounts", 261 Value: eth.DefaultConfig.TxPool.GlobalQueue, 262 } 263 TxPoolLifetimeFlag = cli.DurationFlag{ 264 Name: "txpool.lifetime", 265 Usage: "Maximum amount of time non-executable transaction are queued", 266 Value: eth.DefaultConfig.TxPool.Lifetime, 267 } 268 // Performance tuning settings 269 CacheFlag = cli.IntFlag{ 270 Name: "cache", 271 Usage: "Megabytes of memory allocated to internal caching", 272 Value: 1024, 273 } 274 CacheDatabaseFlag = cli.IntFlag{ 275 Name: "cache.database", 276 Usage: "Percentage of cache memory allowance to use for database io", 277 Value: 75, 278 } 279 CacheGCFlag = cli.IntFlag{ 280 Name: "cache.gc", 281 Usage: "Percentage of cache memory allowance to use for trie pruning", 282 Value: 25, 283 } 284 TrieCacheGenFlag = cli.IntFlag{ 285 Name: "trie-cache-gens", 286 Usage: "Number of trie node generations to keep in memory", 287 Value: int(state.MaxTrieCacheGen), 288 } 289 // Miner settings 290 MiningEnabledFlag = cli.BoolFlag{ 291 Name: "mine", 292 Usage: "Enable mining", 293 } 294 MinerThreadsFlag = cli.IntFlag{ 295 Name: "miner.threads", 296 Usage: "Number of CPU threads to use for mining", 297 Value: 0, 298 } 299 MinerLegacyThreadsFlag = cli.IntFlag{ 300 Name: "minerthreads", 301 Usage: "Number of CPU threads to use for mining (deprecated, use --miner.threads)", 302 Value: 0, 303 } 304 MinerNotifyFlag = cli.StringFlag{ 305 Name: "miner.notify", 306 Usage: "Comma separated HTTP URL list to notify of new work packages", 307 } 308 MinerGasTargetFlag = cli.Uint64Flag{ 309 Name: "miner.gastarget", 310 Usage: "Target gas floor for mined blocks", 311 Value: params.GenesisGasLimit, 312 } 313 MinerLegacyGasTargetFlag = cli.Uint64Flag{ 314 Name: "targetgaslimit", 315 Usage: "Target gas floor for mined blocks (deprecated, use --miner.gastarget)", 316 Value: params.GenesisGasLimit, 317 } 318 MinerGasPriceFlag = BigFlag{ 319 Name: "miner.gasprice", 320 Usage: "Minimal gas price for mining a transactions", 321 Value: eth.DefaultConfig.MinerGasPrice, 322 } 323 MinerLegacyGasPriceFlag = BigFlag{ 324 Name: "gasprice", 325 Usage: "Minimal gas price for mining a transactions (deprecated, use --miner.gasprice)", 326 Value: eth.DefaultConfig.MinerGasPrice, 327 } 328 MinerEtherbaseFlag = cli.StringFlag{ 329 Name: "miner.etherbase", 330 Usage: "Public address for block mining rewards (default = first account)", 331 Value: "0", 332 } 333 MinerLegacyEtherbaseFlag = cli.StringFlag{ 334 Name: "etherbase", 335 Usage: "Public address for block mining rewards (default = first account, deprecated, use --miner.etherbase)", 336 Value: "0", 337 } 338 MinerExtraDataFlag = cli.StringFlag{ 339 Name: "miner.extradata", 340 Usage: "Block extra data set by the miner (default = client version)", 341 } 342 MinerLegacyExtraDataFlag = cli.StringFlag{ 343 Name: "extradata", 344 Usage: "Block extra data set by the miner (default = client version, deprecated, use --miner.extradata)", 345 } 346 MinerRecommitIntervalFlag = cli.DurationFlag{ 347 Name: "miner.recommit", 348 Usage: "Time interval to recreate the block being mined.", 349 Value: eth.DefaultConfig.MinerRecommit, 350 } 351 // Account settings 352 UnlockedAccountFlag = cli.StringFlag{ 353 Name: "unlock", 354 Usage: "Comma separated list of accounts to unlock", 355 Value: "", 356 } 357 PasswordFileFlag = cli.StringFlag{ 358 Name: "password", 359 Usage: "Password file to use for non-interactive password input", 360 Value: "", 361 } 362 363 VMEnableDebugFlag = cli.BoolFlag{ 364 Name: "vmdebug", 365 Usage: "Record information useful for VM and contract debugging", 366 } 367 // Logging and debug settings 368 EthStatsURLFlag = cli.StringFlag{ 369 Name: "ethstats", 370 Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", 371 } 372 FakePoWFlag = cli.BoolFlag{ 373 Name: "fakepow", 374 Usage: "Disables proof-of-work verification", 375 } 376 NoCompactionFlag = cli.BoolFlag{ 377 Name: "nocompaction", 378 Usage: "Disables db compaction after import", 379 } 380 // RPC settings 381 RPCEnabledFlag = cli.BoolFlag{ 382 Name: "rpc", 383 Usage: "Enable the HTTP-RPC server", 384 } 385 RPCListenAddrFlag = cli.StringFlag{ 386 Name: "rpcaddr", 387 Usage: "HTTP-RPC server listening interface", 388 Value: node.DefaultHTTPHost, 389 } 390 RPCPortFlag = cli.IntFlag{ 391 Name: "rpcport", 392 Usage: "HTTP-RPC server listening port", 393 Value: node.DefaultHTTPPort, 394 } 395 RPCCORSDomainFlag = cli.StringFlag{ 396 Name: "rpccorsdomain", 397 Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", 398 Value: "", 399 } 400 RPCVirtualHostsFlag = cli.StringFlag{ 401 Name: "rpcvhosts", 402 Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", 403 Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","), 404 } 405 RPCApiFlag = cli.StringFlag{ 406 Name: "rpcapi", 407 Usage: "API's offered over the HTTP-RPC interface", 408 Value: "", 409 } 410 IPCDisabledFlag = cli.BoolFlag{ 411 Name: "ipcdisable", 412 Usage: "Disable the IPC-RPC server", 413 } 414 IPCPathFlag = DirectoryFlag{ 415 Name: "ipcpath", 416 Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", 417 } 418 WSEnabledFlag = cli.BoolFlag{ 419 Name: "ws", 420 Usage: "Enable the WS-RPC server", 421 } 422 WSListenAddrFlag = cli.StringFlag{ 423 Name: "wsaddr", 424 Usage: "WS-RPC server listening interface", 425 Value: node.DefaultWSHost, 426 } 427 WSPortFlag = cli.IntFlag{ 428 Name: "wsport", 429 Usage: "WS-RPC server listening port", 430 Value: node.DefaultWSPort, 431 } 432 WSApiFlag = cli.StringFlag{ 433 Name: "wsapi", 434 Usage: "API's offered over the WS-RPC interface", 435 Value: "", 436 } 437 WSAllowedOriginsFlag = cli.StringFlag{ 438 Name: "wsorigins", 439 Usage: "Origins from which to accept websockets requests", 440 Value: "", 441 } 442 ExecFlag = cli.StringFlag{ 443 Name: "exec", 444 Usage: "Execute JavaScript statement", 445 } 446 PreloadJSFlag = cli.StringFlag{ 447 Name: "preload", 448 Usage: "Comma separated list of JavaScript files to preload into the console", 449 } 450 451 // Network Settings 452 MaxPeersFlag = cli.IntFlag{ 453 Name: "maxpeers", 454 Usage: "Maximum number of network peers (network disabled if set to 0)", 455 Value: 25, 456 } 457 MaxPendingPeersFlag = cli.IntFlag{ 458 Name: "maxpendpeers", 459 Usage: "Maximum number of pending connection attempts (defaults used if set to 0)", 460 Value: 0, 461 } 462 ListenPortFlag = cli.IntFlag{ 463 Name: "port", 464 Usage: "Network listening port", 465 Value: 30303, 466 } 467 BootnodesFlag = cli.StringFlag{ 468 Name: "bootnodes", 469 Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)", 470 Value: "", 471 } 472 BootnodesV4Flag = cli.StringFlag{ 473 Name: "bootnodesv4", 474 Usage: "Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)", 475 Value: "", 476 } 477 BootnodesV5Flag = cli.StringFlag{ 478 Name: "bootnodesv5", 479 Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)", 480 Value: "", 481 } 482 NodeKeyFileFlag = cli.StringFlag{ 483 Name: "nodekey", 484 Usage: "P2P node key file", 485 } 486 NodeKeyHexFlag = cli.StringFlag{ 487 Name: "nodekeyhex", 488 Usage: "P2P node key as hex (for testing)", 489 } 490 NATFlag = cli.StringFlag{ 491 Name: "nat", 492 Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)", 493 Value: "any", 494 } 495 NoDiscoverFlag = cli.BoolFlag{ 496 Name: "nodiscover", 497 Usage: "Disables the peer discovery mechanism (manual peer addition)", 498 } 499 DiscoveryV5Flag = cli.BoolFlag{ 500 Name: "v5disc", 501 Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", 502 } 503 NetrestrictFlag = cli.StringFlag{ 504 Name: "netrestrict", 505 Usage: "Restricts network communication to the given IP networks (CIDR masks)", 506 } 507 508 // ATM the url is left to the user and deployment to 509 JSpathFlag = cli.StringFlag{ 510 Name: "jspath", 511 Usage: "JavaScript root path for `loadScript`", 512 Value: ".", 513 } 514 515 // Gas price oracle settings 516 GpoBlocksFlag = cli.IntFlag{ 517 Name: "gpoblocks", 518 Usage: "Number of recent blocks to check for gas prices", 519 Value: eth.DefaultConfig.GPO.Blocks, 520 } 521 GpoPercentileFlag = cli.IntFlag{ 522 Name: "gpopercentile", 523 Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices", 524 Value: eth.DefaultConfig.GPO.Percentile, 525 } 526 WhisperEnabledFlag = cli.BoolFlag{ 527 Name: "shh", 528 Usage: "Enable Whisper", 529 } 530 WhisperMaxMessageSizeFlag = cli.IntFlag{ 531 Name: "shh.maxmessagesize", 532 Usage: "Max message size accepted", 533 Value: int(whisper.DefaultMaxMessageSize), 534 } 535 WhisperMinPOWFlag = cli.Float64Flag{ 536 Name: "shh.pow", 537 Usage: "Minimum POW accepted", 538 Value: whisper.DefaultMinimumPoW, 539 } 540 541 // Metrics flags 542 MetricsEnabledFlag = cli.BoolFlag{ 543 Name: metrics.MetricsEnabledFlag, 544 Usage: "Enable metrics collection and reporting", 545 } 546 MetricsEnableInfluxDBFlag = cli.BoolFlag{ 547 Name: "metrics.influxdb", 548 Usage: "Enable metrics export/push to an external InfluxDB database", 549 } 550 MetricsInfluxDBEndpointFlag = cli.StringFlag{ 551 Name: "metrics.influxdb.endpoint", 552 Usage: "InfluxDB API endpoint to report metrics to", 553 Value: "http://localhost:8086", 554 } 555 MetricsInfluxDBDatabaseFlag = cli.StringFlag{ 556 Name: "metrics.influxdb.database", 557 Usage: "InfluxDB database name to push reported metrics to", 558 Value: "geth", 559 } 560 MetricsInfluxDBUsernameFlag = cli.StringFlag{ 561 Name: "metrics.influxdb.username", 562 Usage: "Username to authorize access to the database", 563 Value: "test", 564 } 565 MetricsInfluxDBPasswordFlag = cli.StringFlag{ 566 Name: "metrics.influxdb.password", 567 Usage: "Password to authorize access to the database", 568 Value: "test", 569 } 570 // The `host` tag is part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. 571 // It is used so that we can group all nodes and average a measurement across all of them, but also so 572 // that we can select a specific node and inspect its measurements. 573 // https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key 574 MetricsInfluxDBHostTagFlag = cli.StringFlag{ 575 Name: "metrics.influxdb.host.tag", 576 Usage: "InfluxDB `host` tag attached to all measurements", 577 Value: "localhost", 578 } 579 ) 580 581 // MakeDataDir retrieves the currently requested data directory, terminating 582 // if none (or the empty string) is specified. If the node is starting a testnet, 583 // the a subdirectory of the specified datadir will be used. 584 func MakeDataDir(ctx *cli.Context) string { 585 if path := ctx.GlobalString(DataDirFlag.Name); path != "" { 586 if ctx.GlobalBool(TestnetFlag.Name) { 587 return filepath.Join(path, "testnet") 588 } 589 if ctx.GlobalBool(RinkebyFlag.Name) { 590 return filepath.Join(path, "rinkeby") 591 } 592 return path 593 } 594 Fatalf("Cannot determine default data directory, please set manually (--datadir)") 595 return "" 596 } 597 598 // setNodeKey creates a node key from set command line flags, either loading it 599 // from a file or as a specified hex value. If neither flags were provided, this 600 // method returns nil and an emphemeral key is to be generated. 601 func setNodeKey(ctx *cli.Context, cfg *p2p.Config) { 602 var ( 603 hex = ctx.GlobalString(NodeKeyHexFlag.Name) 604 file = ctx.GlobalString(NodeKeyFileFlag.Name) 605 key *ecdsa.PrivateKey 606 err error 607 ) 608 switch { 609 case file != "" && hex != "": 610 Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name) 611 case file != "": 612 if key, err = crypto.LoadECDSA(file); err != nil { 613 Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err) 614 } 615 cfg.PrivateKey = key 616 case hex != "": 617 if key, err = crypto.HexToECDSA(hex); err != nil { 618 Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err) 619 } 620 cfg.PrivateKey = key 621 } 622 } 623 624 // setNodeUserIdent creates the user identifier from CLI flags. 625 func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) { 626 if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 { 627 cfg.UserIdent = identity 628 } 629 } 630 631 // setBootstrapNodes creates a list of bootstrap nodes from the command line 632 // flags, reverting to pre-configured ones if none have been specified. 633 func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { 634 urls := params.MainnetBootnodes 635 switch { 636 case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name): 637 if ctx.GlobalIsSet(BootnodesV4Flag.Name) { 638 urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",") 639 } else { 640 urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") 641 } 642 case ctx.GlobalBool(TestnetFlag.Name): 643 urls = params.TestnetBootnodes 644 case ctx.GlobalBool(RinkebyFlag.Name): 645 urls = params.RinkebyBootnodes 646 case cfg.BootstrapNodes != nil: 647 return // already set, don't apply defaults. 648 } 649 650 cfg.BootstrapNodes = make([]*discover.Node, 0, len(urls)) 651 for _, url := range urls { 652 node, err := discover.ParseNode(url) 653 if err != nil { 654 log.Crit("Bootstrap URL invalid", "enode", url, "err", err) 655 } 656 cfg.BootstrapNodes = append(cfg.BootstrapNodes, node) 657 } 658 } 659 660 // setBootstrapNodesV5 creates a list of bootstrap nodes from the command line 661 // flags, reverting to pre-configured ones if none have been specified. 662 func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { 663 urls := params.DiscoveryV5Bootnodes 664 switch { 665 case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name): 666 if ctx.GlobalIsSet(BootnodesV5Flag.Name) { 667 urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",") 668 } else { 669 urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") 670 } 671 case ctx.GlobalBool(RinkebyFlag.Name): 672 urls = params.RinkebyBootnodes 673 case cfg.BootstrapNodesV5 != nil: 674 return // already set, don't apply defaults. 675 } 676 677 cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls)) 678 for _, url := range urls { 679 node, err := discv5.ParseNode(url) 680 if err != nil { 681 log.Error("Bootstrap URL invalid", "enode", url, "err", err) 682 continue 683 } 684 cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node) 685 } 686 } 687 688 // setListenAddress creates a TCP listening address string from set command 689 // line flags. 690 func setListenAddress(ctx *cli.Context, cfg *p2p.Config) { 691 if ctx.GlobalIsSet(ListenPortFlag.Name) { 692 cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)) 693 } 694 } 695 696 // setNAT creates a port mapper from command line flags. 697 func setNAT(ctx *cli.Context, cfg *p2p.Config) { 698 if ctx.GlobalIsSet(NATFlag.Name) { 699 natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) 700 if err != nil { 701 Fatalf("Option %s: %v", NATFlag.Name, err) 702 } 703 cfg.NAT = natif 704 } 705 } 706 707 // splitAndTrim splits input separated by a comma 708 // and trims excessive white space from the substrings. 709 func splitAndTrim(input string) []string { 710 result := strings.Split(input, ",") 711 for i, r := range result { 712 result[i] = strings.TrimSpace(r) 713 } 714 return result 715 } 716 717 // setHTTP creates the HTTP RPC listener interface string from the set 718 // command line flags, returning empty if the HTTP endpoint is disabled. 719 func setHTTP(ctx *cli.Context, cfg *node.Config) { 720 if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" { 721 cfg.HTTPHost = "127.0.0.1" 722 if ctx.GlobalIsSet(RPCListenAddrFlag.Name) { 723 cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name) 724 } 725 } 726 727 if ctx.GlobalIsSet(RPCPortFlag.Name) { 728 cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name) 729 } 730 if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) { 731 cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name)) 732 } 733 if ctx.GlobalIsSet(RPCApiFlag.Name) { 734 cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name)) 735 } 736 if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) { 737 cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name)) 738 } 739 } 740 741 // setWS creates the WebSocket RPC listener interface string from the set 742 // command line flags, returning empty if the HTTP endpoint is disabled. 743 func setWS(ctx *cli.Context, cfg *node.Config) { 744 if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" { 745 cfg.WSHost = "127.0.0.1" 746 if ctx.GlobalIsSet(WSListenAddrFlag.Name) { 747 cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name) 748 } 749 } 750 751 if ctx.GlobalIsSet(WSPortFlag.Name) { 752 cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name) 753 } 754 if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) { 755 cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name)) 756 } 757 if ctx.GlobalIsSet(WSApiFlag.Name) { 758 cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name)) 759 } 760 } 761 762 // setIPC creates an IPC path configuration from the set command line flags, 763 // returning an empty string if IPC was explicitly disabled, or the set path. 764 func setIPC(ctx *cli.Context, cfg *node.Config) { 765 checkExclusive(ctx, IPCDisabledFlag, IPCPathFlag) 766 switch { 767 case ctx.GlobalBool(IPCDisabledFlag.Name): 768 cfg.IPCPath = "" 769 case ctx.GlobalIsSet(IPCPathFlag.Name): 770 cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name) 771 } 772 } 773 774 // makeDatabaseHandles raises out the number of allowed file handles per process 775 // for Geth and returns half of the allowance to assign to the database. 776 func makeDatabaseHandles() int { 777 limit, err := fdlimit.Current() 778 if err != nil { 779 Fatalf("Failed to retrieve file descriptor allowance: %v", err) 780 } 781 if limit < 2048 { 782 if err := fdlimit.Raise(2048); err != nil { 783 Fatalf("Failed to raise file descriptor allowance: %v", err) 784 } 785 } 786 if limit > 2048 { // cap database file descriptors even if more is available 787 limit = 2048 788 } 789 return limit / 2 // Leave half for networking and other stuff 790 } 791 792 // MakeAddress converts an account specified directly as a hex encoded string or 793 // a key index in the key store to an internal account representation. 794 func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) { 795 // If the specified account is a valid address, return it 796 if common.IsHexAddress(account) { 797 return accounts.Account{Address: common.HexToAddress(account)}, nil 798 } 799 // Otherwise try to interpret the account as a keystore index 800 index, err := strconv.Atoi(account) 801 if err != nil || index < 0 { 802 return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account) 803 } 804 log.Warn("-------------------------------------------------------------------") 805 log.Warn("Referring to accounts by order in the keystore folder is dangerous!") 806 log.Warn("This functionality is deprecated and will be removed in the future!") 807 log.Warn("Please use explicit addresses! (can search via `geth account list`)") 808 log.Warn("-------------------------------------------------------------------") 809 810 accs := ks.Accounts() 811 if len(accs) <= index { 812 return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs)) 813 } 814 return accs[index], nil 815 } 816 817 // setEtherbase retrieves the etherbase either from the directly specified 818 // command line flags or from the keystore if CLI indexed. 819 func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) { 820 // Extract the current etherbase, new flag overriding legacy one 821 var etherbase string 822 if ctx.GlobalIsSet(MinerLegacyEtherbaseFlag.Name) { 823 etherbase = ctx.GlobalString(MinerLegacyEtherbaseFlag.Name) 824 } 825 if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) { 826 etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name) 827 } 828 // Convert the etherbase into an address and configure it 829 if etherbase != "" { 830 account, err := MakeAddress(ks, etherbase) 831 if err != nil { 832 Fatalf("Invalid miner etherbase: %v", err) 833 } 834 cfg.Etherbase = account.Address 835 } 836 } 837 838 // MakePasswordList reads password lines from the file specified by the global --password flag. 839 func MakePasswordList(ctx *cli.Context) []string { 840 path := ctx.GlobalString(PasswordFileFlag.Name) 841 if path == "" { 842 return nil 843 } 844 text, err := ioutil.ReadFile(path) 845 if err != nil { 846 Fatalf("Failed to read password file: %v", err) 847 } 848 lines := strings.Split(string(text), "\n") 849 // Sanitise DOS line endings. 850 for i := range lines { 851 lines[i] = strings.TrimRight(lines[i], "\r") 852 } 853 return lines 854 } 855 856 func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { 857 setNodeKey(ctx, cfg) 858 setNAT(ctx, cfg) 859 setListenAddress(ctx, cfg) 860 setBootstrapNodes(ctx, cfg) 861 setBootstrapNodesV5(ctx, cfg) 862 863 lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light" 864 lightServer := ctx.GlobalInt(LightServFlag.Name) != 0 865 lightPeers := ctx.GlobalInt(LightPeersFlag.Name) 866 867 if ctx.GlobalIsSet(MaxPeersFlag.Name) { 868 cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name) 869 if lightServer && !ctx.GlobalIsSet(LightPeersFlag.Name) { 870 cfg.MaxPeers += lightPeers 871 } 872 } else { 873 if lightServer { 874 cfg.MaxPeers += lightPeers 875 } 876 if lightClient && ctx.GlobalIsSet(LightPeersFlag.Name) && cfg.MaxPeers < lightPeers { 877 cfg.MaxPeers = lightPeers 878 } 879 } 880 if !(lightClient || lightServer) { 881 lightPeers = 0 882 } 883 ethPeers := cfg.MaxPeers - lightPeers 884 if lightClient { 885 ethPeers = 0 886 } 887 log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers) 888 889 if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) { 890 cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name) 891 } 892 if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient { 893 cfg.NoDiscovery = true 894 } 895 896 // if we're running a light client or server, force enable the v5 peer discovery 897 // unless it is explicitly disabled with --nodiscover note that explicitly specifying 898 // --v5disc overrides --nodiscover, in which case the later only disables v4 discovery 899 forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name) 900 if ctx.GlobalIsSet(DiscoveryV5Flag.Name) { 901 cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name) 902 } else if forceV5Discovery { 903 cfg.DiscoveryV5 = true 904 } 905 906 if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" { 907 list, err := netutil.ParseNetlist(netrestrict) 908 if err != nil { 909 Fatalf("Option %q: %v", NetrestrictFlag.Name, err) 910 } 911 cfg.NetRestrict = list 912 } 913 914 if ctx.GlobalBool(DeveloperFlag.Name) { 915 // --dev mode can't use p2p networking. 916 cfg.MaxPeers = 0 917 cfg.ListenAddr = ":0" 918 cfg.NoDiscovery = true 919 cfg.DiscoveryV5 = false 920 } 921 } 922 923 // SetNodeConfig applies node-related command line flags to the config. 924 func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { 925 SetP2PConfig(ctx, &cfg.P2P) 926 setIPC(ctx, cfg) 927 setHTTP(ctx, cfg) 928 setWS(ctx, cfg) 929 setNodeUserIdent(ctx, cfg) 930 931 switch { 932 case ctx.GlobalIsSet(DataDirFlag.Name): 933 cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) 934 case ctx.GlobalBool(DeveloperFlag.Name): 935 cfg.DataDir = "" // unless explicitly requested, use memory databases 936 case ctx.GlobalBool(TestnetFlag.Name): 937 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet") 938 case ctx.GlobalBool(RinkebyFlag.Name): 939 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") 940 } 941 942 if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { 943 cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name) 944 } 945 if ctx.GlobalIsSet(LightKDFFlag.Name) { 946 cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name) 947 } 948 if ctx.GlobalIsSet(NoUSBFlag.Name) { 949 cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name) 950 } 951 } 952 953 func setGPO(ctx *cli.Context, cfg *gasprice.Config) { 954 if ctx.GlobalIsSet(GpoBlocksFlag.Name) { 955 cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name) 956 } 957 if ctx.GlobalIsSet(GpoPercentileFlag.Name) { 958 cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name) 959 } 960 } 961 962 func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { 963 if ctx.GlobalIsSet(TxPoolLocalsFlag.Name) { 964 locals := strings.Split(ctx.GlobalString(TxPoolLocalsFlag.Name), ",") 965 for _, account := range locals { 966 if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) { 967 Fatalf("Invalid account in --txpool.locals: %s", trimmed) 968 } else { 969 cfg.Locals = append(cfg.Locals, common.HexToAddress(account)) 970 } 971 } 972 } 973 if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { 974 cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) 975 } 976 if ctx.GlobalIsSet(TxPoolJournalFlag.Name) { 977 cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name) 978 } 979 if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) { 980 cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name) 981 } 982 if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) { 983 cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name) 984 } 985 if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) { 986 cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name) 987 } 988 if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) { 989 cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name) 990 } 991 if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) { 992 cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name) 993 } 994 if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) { 995 cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name) 996 } 997 if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) { 998 cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name) 999 } 1000 if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) { 1001 cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name) 1002 } 1003 } 1004 1005 func setEthash(ctx *cli.Context, cfg *eth.Config) { 1006 if ctx.GlobalIsSet(EthashCacheDirFlag.Name) { 1007 cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name) 1008 } 1009 if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) { 1010 cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name) 1011 } 1012 if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) { 1013 cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name) 1014 } 1015 if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) { 1016 cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name) 1017 } 1018 if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) { 1019 cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name) 1020 } 1021 if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) { 1022 cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name) 1023 } 1024 } 1025 1026 // checkExclusive verifies that only a single instance of the provided flags was 1027 // set by the user. Each flag might optionally be followed by a string type to 1028 // specialize it further. 1029 func checkExclusive(ctx *cli.Context, args ...interface{}) { 1030 set := make([]string, 0, 1) 1031 for i := 0; i < len(args); i++ { 1032 // Make sure the next argument is a flag and skip if not set 1033 flag, ok := args[i].(cli.Flag) 1034 if !ok { 1035 panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i])) 1036 } 1037 // Check if next arg extends current and expand its name if so 1038 name := flag.GetName() 1039 1040 if i+1 < len(args) { 1041 switch option := args[i+1].(type) { 1042 case string: 1043 // Extended flag, expand the name and shift the arguments 1044 if ctx.GlobalString(flag.GetName()) == option { 1045 name += "=" + option 1046 } 1047 i++ 1048 1049 case cli.Flag: 1050 default: 1051 panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1])) 1052 } 1053 } 1054 // Mark the flag if it's set 1055 if ctx.GlobalIsSet(flag.GetName()) { 1056 set = append(set, "--"+name) 1057 } 1058 } 1059 if len(set) > 1 { 1060 Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", ")) 1061 } 1062 } 1063 1064 // SetShhConfig applies shh-related command line flags to the config. 1065 func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) { 1066 if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) { 1067 cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name)) 1068 } 1069 if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) { 1070 cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name) 1071 } 1072 } 1073 1074 // SetEthConfig applies eth-related command line flags to the config. 1075 func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { 1076 // Avoid conflicting network flags 1077 checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag) 1078 checkExclusive(ctx, LightServFlag, SyncModeFlag, "light") 1079 1080 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 1081 setEtherbase(ctx, ks, cfg) 1082 setGPO(ctx, &cfg.GPO) 1083 setTxPool(ctx, &cfg.TxPool) 1084 setEthash(ctx, cfg) 1085 1086 if ctx.GlobalIsSet(SyncModeFlag.Name) { 1087 cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) 1088 } 1089 if ctx.GlobalIsSet(LightServFlag.Name) { 1090 cfg.LightServ = ctx.GlobalInt(LightServFlag.Name) 1091 } 1092 if ctx.GlobalIsSet(LightPeersFlag.Name) { 1093 cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name) 1094 } 1095 if ctx.GlobalIsSet(NetworkIdFlag.Name) { 1096 cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) 1097 } 1098 1099 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { 1100 cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 1101 } 1102 cfg.DatabaseHandles = makeDatabaseHandles() 1103 1104 if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { 1105 Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) 1106 } 1107 cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive" 1108 1109 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { 1110 cfg.TrieCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 1111 } 1112 if ctx.GlobalIsSet(MinerLegacyThreadsFlag.Name) { 1113 cfg.MinerThreads = ctx.GlobalInt(MinerLegacyThreadsFlag.Name) 1114 } 1115 if ctx.GlobalIsSet(MinerThreadsFlag.Name) { 1116 cfg.MinerThreads = ctx.GlobalInt(MinerThreadsFlag.Name) 1117 } 1118 if ctx.GlobalIsSet(MinerNotifyFlag.Name) { 1119 cfg.MinerNotify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",") 1120 } 1121 if ctx.GlobalIsSet(DocRootFlag.Name) { 1122 cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name) 1123 } 1124 if ctx.GlobalIsSet(MinerLegacyExtraDataFlag.Name) { 1125 cfg.MinerExtraData = []byte(ctx.GlobalString(MinerLegacyExtraDataFlag.Name)) 1126 } 1127 if ctx.GlobalIsSet(MinerExtraDataFlag.Name) { 1128 cfg.MinerExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name)) 1129 } 1130 if ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) { 1131 cfg.MinerGasPrice = GlobalBig(ctx, MinerLegacyGasPriceFlag.Name) 1132 } 1133 if ctx.GlobalIsSet(MinerGasPriceFlag.Name) { 1134 cfg.MinerGasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name) 1135 } 1136 if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) { 1137 cfg.MinerRecommit = ctx.Duration(MinerRecommitIntervalFlag.Name) 1138 } 1139 if ctx.GlobalIsSet(VMEnableDebugFlag.Name) { 1140 // TODO(fjl): force-enable this in --dev mode 1141 cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name) 1142 } 1143 1144 // Override any default configs for hard coded networks. 1145 switch { 1146 case ctx.GlobalBool(TestnetFlag.Name): 1147 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1148 cfg.NetworkId = 3 1149 } 1150 cfg.Genesis = core.DefaultTestnetGenesisBlock() 1151 case ctx.GlobalBool(RinkebyFlag.Name): 1152 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1153 cfg.NetworkId = 4 1154 } 1155 cfg.Genesis = core.DefaultRinkebyGenesisBlock() 1156 case ctx.GlobalBool(DeveloperFlag.Name): 1157 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1158 cfg.NetworkId = 1337 1159 } 1160 // Create new developer account or reuse existing one 1161 var ( 1162 developer accounts.Account 1163 err error 1164 ) 1165 if accs := ks.Accounts(); len(accs) > 0 { 1166 developer = ks.Accounts()[0] 1167 } else { 1168 developer, err = ks.NewAccount("") 1169 if err != nil { 1170 Fatalf("Failed to create developer account: %v", err) 1171 } 1172 } 1173 if err := ks.Unlock(developer, ""); err != nil { 1174 Fatalf("Failed to unlock developer account: %v", err) 1175 } 1176 log.Info("Using developer account", "address", developer.Address) 1177 1178 cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address) 1179 if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) { 1180 cfg.MinerGasPrice = big.NewInt(1) 1181 } 1182 } 1183 // TODO(fjl): move trie cache generations into config 1184 if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 { 1185 state.MaxTrieCacheGen = uint16(gen) 1186 } 1187 } 1188 1189 // RegisterEthService adds an Ethereum client to the stack. 1190 func RegisterEthService(stack *node.Node, cfg *eth.Config) { 1191 var err error 1192 if cfg.SyncMode == downloader.LightSync { 1193 err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1194 return les.New(ctx, cfg) 1195 }) 1196 } else { 1197 err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1198 fullNode, err := eth.New(ctx, cfg) 1199 if fullNode != nil && cfg.LightServ > 0 { 1200 ls, _ := les.NewLesServer(fullNode, cfg) 1201 fullNode.AddLesServer(ls) 1202 } 1203 return fullNode, err 1204 }) 1205 } 1206 if err != nil { 1207 Fatalf("Failed to register the Ethereum service: %v", err) 1208 } 1209 } 1210 1211 // RegisterShhService configures Whisper and adds it to the given node. 1212 func RegisterShhService(stack *node.Node, cfg *whisper.Config) { 1213 if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) { 1214 return whisper.New(cfg), nil 1215 }); err != nil { 1216 Fatalf("Failed to register the Whisper service: %v", err) 1217 } 1218 } 1219 1220 // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to 1221 // the given node. 1222 func RegisterEthStatsService(stack *node.Node, url string) { 1223 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1224 // Retrieve both eth and les services 1225 var ethServ *eth.Ethereum 1226 ctx.Service(ðServ) 1227 1228 var lesServ *les.LightEthereum 1229 ctx.Service(&lesServ) 1230 1231 return ethstats.New(url, ethServ, lesServ) 1232 }); err != nil { 1233 Fatalf("Failed to register the Ethereum Stats service: %v", err) 1234 } 1235 } 1236 1237 // SetupNetwork configures the system for either the main net or some test network. 1238 func SetupNetwork(ctx *cli.Context) { 1239 // TODO(fjl): move target gas limit into config 1240 params.TargetGasLimit = ctx.GlobalUint64(MinerLegacyGasTargetFlag.Name) 1241 if ctx.GlobalIsSet(MinerGasTargetFlag.Name) { 1242 params.TargetGasLimit = ctx.GlobalUint64(MinerGasTargetFlag.Name) 1243 } 1244 } 1245 1246 func SetupMetrics(ctx *cli.Context) { 1247 if metrics.Enabled { 1248 log.Info("Enabling metrics collection") 1249 var ( 1250 enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name) 1251 endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) 1252 database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) 1253 username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) 1254 password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name) 1255 hosttag = ctx.GlobalString(MetricsInfluxDBHostTagFlag.Name) 1256 ) 1257 1258 if enableExport { 1259 log.Info("Enabling metrics export to InfluxDB") 1260 go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", map[string]string{ 1261 "host": hosttag, 1262 }) 1263 } 1264 } 1265 } 1266 1267 // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. 1268 func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { 1269 var ( 1270 cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 1271 handles = makeDatabaseHandles() 1272 ) 1273 name := "chaindata" 1274 if ctx.GlobalString(SyncModeFlag.Name) == "light" { 1275 name = "lightchaindata" 1276 } 1277 chainDb, err := stack.OpenDatabase(name, cache, handles) 1278 if err != nil { 1279 Fatalf("Could not open database: %v", err) 1280 } 1281 return chainDb 1282 } 1283 1284 func MakeGenesis(ctx *cli.Context) *core.Genesis { 1285 var genesis *core.Genesis 1286 switch { 1287 case ctx.GlobalBool(TestnetFlag.Name): 1288 genesis = core.DefaultTestnetGenesisBlock() 1289 case ctx.GlobalBool(RinkebyFlag.Name): 1290 genesis = core.DefaultRinkebyGenesisBlock() 1291 case ctx.GlobalBool(DeveloperFlag.Name): 1292 Fatalf("Developer chains are ephemeral") 1293 } 1294 return genesis 1295 } 1296 1297 // MakeChain creates a chain manager from set command line flags. 1298 func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { 1299 var err error 1300 chainDb = MakeChainDatabase(ctx, stack) 1301 1302 config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) 1303 if err != nil { 1304 Fatalf("%v", err) 1305 } 1306 var engine consensus.Engine 1307 if config.Clique != nil { 1308 engine = clique.New(config.Clique, chainDb) 1309 } else { 1310 engine = ethash.NewFaker() 1311 if !ctx.GlobalBool(FakePoWFlag.Name) { 1312 engine = ethash.New(ethash.Config{ 1313 CacheDir: stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir), 1314 CachesInMem: eth.DefaultConfig.Ethash.CachesInMem, 1315 CachesOnDisk: eth.DefaultConfig.Ethash.CachesOnDisk, 1316 DatasetDir: stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir), 1317 DatasetsInMem: eth.DefaultConfig.Ethash.DatasetsInMem, 1318 DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk, 1319 }, nil) 1320 } 1321 } 1322 if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { 1323 Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) 1324 } 1325 cache := &core.CacheConfig{ 1326 Disabled: ctx.GlobalString(GCModeFlag.Name) == "archive", 1327 TrieNodeLimit: eth.DefaultConfig.TrieCache, 1328 TrieTimeLimit: eth.DefaultConfig.TrieTimeout, 1329 } 1330 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { 1331 cache.TrieNodeLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 1332 } 1333 vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} 1334 chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg) 1335 if err != nil { 1336 Fatalf("Can't create BlockChain: %v", err) 1337 } 1338 return chain, chainDb 1339 } 1340 1341 // MakeConsolePreloads retrieves the absolute paths for the console JavaScript 1342 // scripts to preload before starting. 1343 func MakeConsolePreloads(ctx *cli.Context) []string { 1344 // Skip preloading if there's nothing to preload 1345 if ctx.GlobalString(PreloadJSFlag.Name) == "" { 1346 return nil 1347 } 1348 // Otherwise resolve absolute paths and return them 1349 preloads := []string{} 1350 1351 assets := ctx.GlobalString(JSpathFlag.Name) 1352 for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { 1353 preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file))) 1354 } 1355 return preloads 1356 } 1357 1358 // MigrateFlags sets the global flag from a local flag when it's set. 1359 // This is a temporary function used for migrating old command/flags to the 1360 // new format. 1361 // 1362 // e.g. geth account new --keystore /tmp/mykeystore --lightkdf 1363 // 1364 // is equivalent after calling this method with: 1365 // 1366 // geth --keystore /tmp/mykeystore --lightkdf account new 1367 // 1368 // This allows the use of the existing configuration functionality. 1369 // When all flags are migrated this function can be removed and the existing 1370 // configuration functionality must be changed that is uses local flags 1371 func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error { 1372 return func(ctx *cli.Context) error { 1373 for _, name := range ctx.FlagNames() { 1374 if ctx.IsSet(name) { 1375 ctx.GlobalSet(name, ctx.String(name)) 1376 } 1377 } 1378 return action(ctx) 1379 } 1380 }