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